0% found this document useful (0 votes)
5 views

java unit2

The document provides an overview of multithreaded programming in Java, focusing on the join() and isAlive() methods, which manage thread execution and check thread status. It also discusses synchronization to prevent race conditions, the Java I/O API for handling input and output operations, and the types of exceptions in Java, including checked and unchecked exceptions. Key concepts include thread creation, synchronization using the synchronized keyword, and the distinction between byte and character streams in file handling.

Uploaded by

abhaysingh17772
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

java unit2

The document provides an overview of multithreaded programming in Java, focusing on the join() and isAlive() methods, which manage thread execution and check thread status. It also discusses synchronization to prevent race conditions, the Java I/O API for handling input and output operations, and the types of exceptions in Java, including checked and unchecked exceptions. Key concepts include thread creation, synchronization using the synchronized keyword, and the distinction between byte and character streams in file handling.

Uploaded by

abhaysingh17772
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

Here’s a written explanation you can use in your exam for Multithreaded Programming in Java with

a focus on join() and isAlive() methods.

Multithreaded Programming in Java

Java allows the creation of multi-threaded programs where multiple threads can execute
simultaneously. Threads are the smallest unit of a process. In Java, we can create threads in two
ways:

1. By implementing the Runnable interface

2. By extending the Thread class

Both methods require overriding the run() method, which defines the code that will be executed by
the thread.

Thread Methods:

Method Purpose

start() Starts the execution of the thread by calling the run() method internally.

stop() Terminates the thread (deprecated in Java).

Sets the thread's priority (values: Thread.MIN_PRIORITY, Thread.NORM_PRIORITY,


setPriority()
Thread.MAX_PRIORITY).

sleep(long
Pauses the thread execution for the specified number of milliseconds.
millis)

isAlive() Checks if the thread is still running.

Causes the current thread to wait until the thread it’s called on has completed
join()
execution.

Key Example Using isAlive() and join()

java

CopyEdit

class ThDemo implements Runnable {

Thread t;

String name;

public ThDemo(String n) {
name = n;

t = new Thread(this); // Create a new thread.

t.start(); // Start the thread.

public void run() {

for (int i = 1; i <= 5; i++) {

System.out.println(name); // Print thread name.

try {

Thread.sleep(2000); // Sleep for 2 seconds.

} catch (InterruptedException e) {

System.out.println(e);

System.out.println(name + " Thread is Exiting.....");

class Test {

public static void main(String[] args) {

ThDemo t1 = new ThDemo("Hello");

ThDemo t2 = new ThDemo("Hi");

ThDemo t3 = new ThDemo("Bye");

// Before threads finish execution, check if they're alive.

System.out.println("Hello Thread is Working: " + t1.t.isAlive());

System.out.println("Hi Thread is Working: " + t2.t.isAlive());

System.out.println("Bye Thread is Working: " + t3.t.isAlive());

try {

// Wait for all threads to finish using join().


t1.t.join();

t2.t.join();

t3.t.join();

} catch (InterruptedException e) {

System.out.println(e);

// After threads finish, check if they're alive again.

System.out.println("Hello Thread is Working: " + t1.t.isAlive());

System.out.println("Hi Thread is Working: " + t2.t.isAlive());

System.out.println("Bye Thread is Working: " + t3.t.isAlive());

System.out.println("main() Thread is Exiting.....");

Explanation of isAlive() and join():

1. isAlive() Method:

o Before calling join(), the isAlive() method checks if a thread is still in the running
state.

o After a thread has completed its execution, isAlive() returns false.

2. join() Method:

o This method ensures that the main thread waits for each thread (like t1, t2, t3 in the
example) to complete execution before it proceeds.

o The main thread will pause at the join() method call until the thread it is called on
finishes.

Execution Flow Example:

1. Before Calling join():

o Threads are in the running state (alive).

o isAlive() returns true.

2. After Calling join():


o The main thread waits for each thread to finish execution (using join()).

o Once each thread completes, the main thread resumes and checks again using
isAlive().

o At this point, isAlive() returns false for each thread, indicating they are no longer
alive.

Summary of Important Points:

• start(): Initiates a thread to begin its execution.

• run(): Defines the task the thread will execute.

• join(): Ensures that the main thread waits for a thread to finish before proceeding.

• isAlive(): Checks if a thread is still running or has finished execution.

These methods are essential in managing multithreading and ensuring that threads run efficiently
and in a controlled order.

This written explanation should help you understand how the isAlive() and join() methods work in
Java, allowing you to effectively use them in your multi-threaded programs.

Let me know if you need further clarification on any part!

Synchronization in Threads

In Java, synchronization is used to prevent the race condition when multiple threads try to access a
shared resource. When multiple threads attempt to access the same resource concurrently, data
corruption or inconsistent results can occur. Synchronization ensures that only one thread can access
the shared resource at a time.

Key Points about Synchronization:

• synchronized keyword: This keyword is used to make a method or block of code thread-safe
by allowing only one thread to execute it at any given time.

• When multiple threads try to access a synchronized method on the same object, only one
thread is allowed to enter the method at a time, while others are blocked until the current
thread finishes.

Example Explanation with Code:

The example code you provided demonstrates the usage of synchronization using the synchronized
keyword.
Code:

java

CopyEdit

class CallMe {

// Synchronized method to ensure only one thread can access it at a time.

public synchronized void mainFun(String name) {

System.out.print("[" + name);

try {

Thread.sleep(1000); // Simulate some processing time.

} catch (InterruptedException e) {}

System.out.println("]");

class Middle implements Runnable {

CallMe ob; // Reference to the CallMe object

String msg; // Message to be passed

// Constructor

public Middle(CallMe o, String n) {

ob = o; // Assign the passed CallMe object

msg = n; // Assign the passed string

new Thread(this).start(); // Start a new thread for this task.

// Run method for the thread

public void run() {

ob.mainFun(msg); // Call the synchronized method.

}
class Test {

public static void main(String[] args) {

CallMe obj = new CallMe(); // Create an instance of the CallMe class

// Start three threads that will try to access the same method

new Middle(obj, "Dhananjay");

new Middle(obj, "Kumar");

new Middle(obj, "Sharma");

Explanation:

1. The CallMe class:

o The mainFun(String name) method is synchronized, which means only one thread
can execute it at any given time. If another thread tries to call this method while it's
already being executed by one thread, it will be blocked until the current thread
finishes.

2. The Middle class:

o Implements Runnable and calls the synchronized mainFun method on a CallMe


object.

o When the Middle class is instantiated, it starts a new thread that calls the mainFun
method.

3. The Test class:

o Creates an instance of the CallMe class.

o Starts three threads (t1, t2, and t3) that all try to call the synchronized mainFun
method.

What Happens When You Run This Code?

• The three threads (t1, t2, and t3) will try to call the synchronized mainFun method on the
same object obj.

• Since the method is synchronized, only one thread will be able to execute it at any given
time.

• The first thread will print its message, then pause for 1 second (simulated by
Thread.sleep(1000)), and finally print a closing bracket. The second thread will have to wait
for the first to finish before it can start its execution.

• As a result, the output will look like:

csharp
CopyEdit

[Dhananjay]

[Kumar]

[Sharma]

Why Use Synchronization?

• Preventing Data Corruption: In a multi-threaded environment, if multiple threads access and


modify shared data concurrently, the data can become inconsistent. By synchronizing
methods or blocks of code, we ensure that only one thread can modify the shared data at a
time, thus preventing corruption.

• Maintaining Thread Safety: Synchronization helps achieve thread safety by ensuring that
only one thread can execute a method or block of code at a time, reducing the risk of issues
like race conditions.

Things to Keep in Mind:

• Deadlock: If two threads are each waiting for the other to release a lock, neither will
proceed, causing a deadlock. This is a common problem when working with synchronization.

• Performance: Synchronization can slow down the performance because it involves locking
and unlocking, which reduces the number of threads that can access the synchronized
method at the same time.

• Fine-Grained Synchronization: If needed, instead of synchronizing an entire method, you can


synchronize only specific blocks of code using synchronized blocks to reduce the
performance overhead.

Java IO (Input and Output) Overview

In Java, Input and Output (I/O) refers to the process of reading data from an input source (such as a
file, keyboard, or network socket) and writing data to an output destination (such as a file, console,
or network socket). Java provides a comprehensive set of APIs to handle I/O operations, commonly
known as the Java I/O API.

Key Points about Java I/O:

1. Java I/O API helps in reading input and producing output.

2. Java uses streams to perform I/O operations efficiently.

3. The java.io package contains all classes for performing I/O operations.

4. File Handling is one of the core features provided by Java I/O API.

5. Streams represent the flow of data that can be read from or written to.
Streams are used for I/O operations because they make reading and writing data efficient by
representing a continuous flow of data. A stream can be attached to a source (input) or destination
(output) and allows the system to perform I/O operations without needing to manage data in bulk.

Java IO Streams

In Java, a stream is a sequence of data. It’s called a "stream" because, like a stream of water, the data
flows continuously from one source to a destination. Streams have no concept of indexing the data,
and data flows in a linear fashion, one byte or character at a time.

There are two main types of streams in Java I/O:

1. InputStream – Used for reading data from a source.

2. OutputStream – Used for writing data to a destination.

Both of these streams are part of the java.io package.

Types of Streams

1. InputStream:

o Purpose: An InputStream is used to read data from a source such as a file, array,
peripheral device, or socket.

o Base Class: java.io.InputStream is the base class for all input streams in Java.

Methods of InputStream:

o read(): Reads the next byte of data from the input stream.

o mark(int arg): Marks the current position in the stream.

o reset(): Resets the stream to the last marked position.

o close(): Closes the stream and releases any system resources associated with it.

o read(byte[] arg): Reads bytes into an array from the input stream.

o skip(long arg): Skips over the specified number of bytes of data from the input
stream.

Example:

java

CopyEdit

InputStream in = new FileInputStream("input.txt");

int data;

while ((data = in.read()) != -1) {

System.out.print((char) data); // Reading byte by byte


}

in.close();

2. OutputStream:

o Purpose: An OutputStream is used to write data to a destination such as a file, array,


peripheral device, or socket.

o Base Class: java.io.OutputStream is the base class for all output streams in Java.

Methods of OutputStream:

o flush(): Flushes the output stream, ensuring that all buffered data is written out.

o close(): Closes the output stream and releases any system resources associated with
it.

o write(int b): Writes a byte of data to the output stream.

o write(byte[] b): Writes an array of bytes to the output stream.

Example:

java

CopyEdit

OutputStream out = new FileOutputStream("output.txt");

String data = "Hello, world!";

out.write(data.getBytes());

out.close();

Types of Streams in Java I/O:

Java I/O streams are broadly categorized into Byte Streams and Character Streams:

1. Byte Streams:

• Purpose: They handle I/O of raw binary data (e.g., image files, audio files, etc.).

• Classes:

o InputStream

o OutputStream

• These streams read and write data in byte format (8-bit).

• Examples: FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream.

Example:

java
CopyEdit

FileInputStream fileInput = new FileInputStream("image.jpg");

int byteData;

while ((byteData = fileInput.read()) != -1) {

System.out.print(byteData);

fileInput.close();

2. Character Streams:

• Purpose: They handle I/O of character data and are used for reading and writing text files.

• Classes:

o Reader

o Writer

• These streams handle data as 16-bit characters (UTF-16 encoding), making them ideal for
handling text.

• Examples: FileReader, FileWriter, BufferedReader, BufferedWriter.

Example:

java

CopyEdit

FileReader fileReader = new FileReader("textfile.txt");

int character;

while ((character = fileReader.read()) != -1) {

System.out.print((char) character);

fileReader.close();

File Handling in Java I/O

The Java I/O API makes it easy to perform file operations like reading from and writing to files. Java
provides Byte Streams and Character Streams for working with files:

• Byte Streams are used for binary data.

• Character Streams are used for textual data.

Example (Reading a text file using FileReader):

java
CopyEdit

import java.io.*;

public class FileReadingExample {

public static void main(String[] args) throws IOException {

FileReader file = new FileReader("sample.txt");

int data;

while ((data = file.read()) != -1) {

System.out.print((char) data);

file.close();

Conclusion

• Java I/O is essential for working with files, reading data, and producing output based on user
input.

• The Java I/O package provides InputStream and OutputStream classes for handling byte-
level data, and Reader and Writer classes for handling character-level data.

• Java I/O is used to interact with various I/O devices and files through a variety of APIs,
stream classes, and methods provided by the java.io package.

4o mini

Types of Exceptions in Java

Exceptions in Java can be broadly categorized into two main types:

1. Checked Exceptions

2. Unchecked Exceptions

1. Checked Exceptions

Checked exceptions are exceptions that are explicitly checked during the compile-time. These
exceptions are typically caused by conditions outside the program's control, such as file handling,
network issues, database errors, etc. The compiler forces the programmer to handle or declare these
exceptions.

• Examples of Checked Exceptions:

o IOException – Occurs during I/O operations.

o SQLException – Occurs when there is an issue with database operations.

o ClassNotFoundException – Occurs when a class is not found.

o FileNotFoundException – Occurs when a specified file cannot be found.

o InterruptedException – Occurs when a thread is interrupted.

How to handle Checked Exceptions: You are required to handle checked exceptions using try-catch
blocks or by declaring the exception with the throws keyword.

Example:

java

CopyEdit

import java.io.*;

class CheckedExceptionExample {

public static void main(String[] args) {

try {

FileReader file = new FileReader("nonexistentfile.txt"); // Checked Exception

} catch (IOException e) {

System.out.println("IOException occurred: " + e.getMessage());

2. Unchecked Exceptions

Unchecked exceptions are exceptions that occur during the runtime of the program. These
exceptions are typically caused by programming errors, such as logic errors or improper use of data.
Unchecked exceptions are subclasses of the RuntimeException class and do not need to be declared
or handled explicitly.

• Examples of Unchecked Exceptions:

o ArithmeticException – Occurs when an arithmetic operation goes wrong (e.g., divide


by zero).
o NullPointerException – Occurs when attempting to access an object or method on a
null reference.

o ArrayIndexOutOfBoundsException – Occurs when trying to access an array element


with an invalid index.

o ClassCastException – Occurs when trying to cast an object to a subclass that is not


compatible.

o IllegalArgumentException – Occurs when a method receives an illegal or


inappropriate argument.

How to handle Unchecked Exceptions: Although these exceptions can be handled using try-catch
blocks, they are typically not required to be handled explicitly by the programmer. They can be
caught to prevent application crashes, but they do not need to be declared using throws.

Example:

java

CopyEdit

public class UncheckedExceptionExample {

public static void main(String[] args) {

try {

int result = 10 / 0; // Unchecked Exception (ArithmeticException)

} catch (ArithmeticException e) {

System.out.println("ArithmeticException: " + e.getMessage());

Other Types of Exceptions

There are also a few other categories of exceptions based on their occurrence and behavior:

3. Errors

Errors are exceptions that typically represent serious problems that a program cannot recover from.
These are not exceptions in the typical sense, and they are not meant to be caught or handled by the
program.

• Examples of Errors:

o OutOfMemoryError – Occurs when the Java Virtual Machine (JVM) runs out of
memory.
o StackOverflowError – Occurs when the stack of a thread overflows (typically due to
deep recursion).

o VirtualMachineError – Indicates a problem with the JVM.

Note: Errors are usually not handled as they indicate critical problems in the system.

Exception Hierarchy in Java

The exception hierarchy in Java is organized as follows:

• Throwable

o Error (not meant to be caught)

▪ Examples: OutOfMemoryError, StackOverflowError

o Exception (can be caught)

▪ Checked Exceptions

▪ Examples: IOException, SQLException

▪ Unchecked Exceptions (also called RuntimeExceptions)

▪ Examples: ArithmeticException, NullPointerException,


ArrayIndexOutOfBoundsException

Custom Exceptions

In Java, you can also define your own exception classes by extending the Exception or
RuntimeException class.

Example of Custom Exception:

java

CopyEdit

class InvalidAgeException extends Exception {

public InvalidAgeException(String message) {

super(message);

public class CustomExceptionExample {

public static void checkAge(int age) throws InvalidAgeException {

if (age < 18) {


throw new InvalidAgeException("Age must be 18 or older");

} else {

System.out.println("Valid age");

public static void main(String[] args) {

try {

checkAge(16); // Throws custom exception

} catch (InvalidAgeException e) {

System.out.println(e.getMessage());

Conclusion

• Checked Exceptions: Must be either caught or declared to be thrown (e.g., IOException,


SQLException).

• Unchecked Exceptions: These are typically programming errors (e.g., NullPointerException,


ArithmeticException).

• Errors: Severe issues that cannot typically be handled (e.g., OutOfMemoryError).

• Custom Exceptions: You can define your own exceptions for specific scenarios.

JVM Reaction to Exceptions

The Java Virtual Machine (JVM) is responsible for the handling of exceptions during runtime. When
an exception is thrown, the JVM reacts by performing a series of steps:

1. Detecting an Exception

When an exception occurs during program execution, the JVM detects it and looks for the nearest
appropriate exception handler (i.e., a catch block or a method declared with throws).

• If a try-catch block exists in the current method, the JVM executes the corresponding catch
block.

• If no handler exists, the exception propagates to the caller.


• This process continues up the call stack until an exception handler is found, or the JVM
terminates the program.

2. Stack Unwinding

As the exception propagates up the call stack, the JVM begins a process called stack unwinding.
During this process:

• The JVM will check each method in the call stack to find a matching catch block.

• If the method has opened resources (such as files or database connections), the JVM may
execute the finally block to close those resources.

• Once a matching catch block is found, the exception is handled, and the program can
continue execution.

3. Termination of Program

If no exception handler is found by the JVM (after unwinding the stack), the JVM will terminate the
program.

• Example:

java

CopyEdit

public class JVMExceptionExample {

public static void main(String[] args) {

throw new RuntimeException("Uncaught exception");

• The exception is uncaught, and the JVM will print the stack trace to the console, then
terminate the program.

4. Fatal Errors

Certain errors (subclasses of Error, such as OutOfMemoryError or StackOverflowError) indicate


critical problems in the JVM environment or the system itself. These errors are typically not
recoverable, and the JVM will attempt to shut down the application gracefully.

Use of try, catch, finally, throw, throws in Exception


Handling,

In Java, exception handling is a mechanism to handle runtime errors, maintaining the normal flow of
the application. The keywords try, catch, finally, throw, and throws are used in various ways to handle
exceptions in Java. Below is an explanation of each of these keywords and how they work together.
1. try Block

The try block is used to wrap code that may potentially throw an exception. If an exception occurs
within the try block, the JVM immediately transfers control to the corresponding catch block, if one
exists.

• Syntax:

java

CopyEdit

try {

// code that might throw an exception

• Example:

java

CopyEdit

try {

int result = 10 / 0; // This will throw an ArithmeticException

} catch (ArithmeticException e) {

System.out.println("Error: " + e);

2. catch Block

The catch block is used to catch and handle exceptions thrown by the try block. You can specify the
type of exception you want to handle. If an exception of that type occurs, the program flow will jump
to the catch block and execute the code there.

• Syntax:

java

CopyEdit

catch (ExceptionType e) {

// handle exception

• Example:

java
CopyEdit

try {

int result = 10 / 0;

} catch (ArithmeticException e) {

System.out.println("Cannot divide by zero: " + e);

3. finally Block

The finally block is used to execute code that must run regardless of whether an exception occurs or
not. This is often used for cleanup operations, such as closing files, releasing resources, or closing
database connections. Even if an exception is thrown and not caught, the finally block will still
execute.

• Syntax:

java

CopyEdit

finally {

// code that will always execute

• Example:

java

CopyEdit

try {

System.out.println("Inside try block");

} finally {

System.out.println("This will always execute");

• Control Flow:

o If an exception occurs and is caught, the finally block executes after the catch block.

o If no exception occurs, the finally block executes after the try block.

4. throw Keyword
The throw keyword is used to manually throw an exception in a method or block of code. You can
throw exceptions of any type, including custom exceptions.

• Syntax:

java

CopyEdit

throw new ExceptionType("Message");

• Example:

java

CopyEdit

public class ThrowExample {

public static void main(String[] args) {

throw new ArithmeticException("Manually thrown exception");

• Use: This is used when you want to explicitly trigger an exception in your code. For example,
if certain conditions are not met, you may throw an exception to signal an error.

5. throws Keyword

The throws keyword is used in a method declaration to indicate that the method might throw certain
exceptions. It is used to pass the responsibility of handling the exception to the calling method. If a
method declares an exception using throws, the caller is required to handle that exception using a
try-catch block or by declaring it with throws.

• Syntax:

java

CopyEdit

public void methodName() throws ExceptionType1, ExceptionType2 {

// method code

• Example:

java

CopyEdit

public class ThrowsExample {

public static void main(String[] args) {


try {

methodThatThrowsException();

} catch (Exception e) {

System.out.println("Exception caught: " + e);

public static void methodThatThrowsException() throws IOException {

throw new IOException("File not found");

• Use:

o It is used when a method might throw an exception but doesn’t want to handle it
within the method itself.

o The calling method must either handle the exception or declare it using throws.

Combining try, catch, finally, throw, and throws

These keywords can be combined in different ways to handle exceptions effectively.

Example 1: Using try, catch, finally

java

CopyEdit

public class ExceptionExample {

public static void main(String[] args) {

try {

int result = 10 / 0;

} catch (ArithmeticException e) {

System.out.println("Caught an exception: " + e);

} finally {

System.out.println("This will always execute.");

}
}

• Explanation:

o The try block throws an exception due to division by zero.

o The catch block catches and handles the exception.

o The finally block is executed no matter what, ensuring that the necessary cleanup or
logging is performed.

Example 2: Using throw and throws

java

CopyEdit

public class ThrowThrowsExample {

public static void main(String[] args) {

try {

methodThatThrowsException();

} catch (IOException e) {

System.out.println("Caught IOException: " + e);

public static void methodThatThrowsException() throws IOException {

System.out.println("Throwing an exception...");

throw new IOException("This is a custom exception");

• Explanation:

o methodThatThrowsException() throws an IOException using throw.

o The method signature uses throws to declare that it may throw an IOException,
passing the responsibility of handling it to the calling method.

o The calling method (main()) catches the IOException using a try-catch block.

Key Differences

• try: Defines a block of code that may throw exceptions.

• catch: Handles exceptions thrown from a try block.


• finally: A block of code that is always executed, regardless of whether an exception occurs or
not.

• throw: Used to explicitly throw an exception.

• throws: Declares that a method may throw an exception and passes the responsibility of
handling it to the calling method.

Thread in Java:

A thread is a lightweight process, and it is the smallest unit of execution in a program. Java allows for
multithreaded programming, where multiple threads can run concurrently, sharing the same
memory space. Threads can be created in Java using the Thread class or implementing the Runnable
interface.

Threads are commonly used to perform multiple tasks simultaneously, like reading data from a file,
executing background tasks, or responding to user inputs in a graphical user interface (GUI).

Thread Life Cycle:

A thread in Java goes through several states during its life cycle. These states represent different
stages of a thread's execution and are controlled by the Java Virtual Machine (JVM). The thread life
cycle consists of the following states:

1. New (Born State):

o When a thread object is created, it is in the "new" state. In this state, the thread is
not yet started. The thread is only instantiated but not yet eligible for execution.

o Example:

java

CopyEdit

Thread t = new Thread(); // Thread is in 'new' state

2. Runnable:

o After the start() method is invoked on the thread, it enters the runnable state. A
thread in the runnable state is ready to run but is waiting for the CPU to schedule it.
This means it is either actively executing or waiting for the CPU to allocate time for it.

o Example:

java

CopyEdit

t.start(); // Thread moves to 'runnable' state

3. Blocked:
o A thread enters the blocked state when it is waiting for a resource or monitor lock to
be released. For example, if a thread tries to access a synchronized block or method
that another thread has locked, it will be blocked.

o Example:

▪ Thread A may try to access a synchronized method but has to wait until
thread B releases the lock on that method.

4. Waiting:

o A thread enters the waiting state when it is waiting indefinitely for another thread to
perform a specific action. The thread is not using the CPU, and it can only move to
the runnable state when notified by another thread using methods like notify() or
notifyAll().

o Example:

java

CopyEdit

synchronized (obj) {

obj.wait(); // Thread enters 'waiting' state

5. Timed Waiting:

o A thread enters the timed waiting state when it is waiting for a specified period. The
thread will automatically return to the runnable state after the specified waiting time
has elapsed.

o Methods that cause a thread to enter this state include sleep(long milliseconds),
join(long milliseconds), wait(long milliseconds), and Thread.sleep().

o Example:

java

CopyEdit

t.sleep(1000); // Thread enters 'timed waiting' state for 1 second

6. Terminated (Dead):

o A thread enters the terminated state when its run() method completes execution, or
if it is terminated due to an exception or interruption. Once a thread has finished
execution, it cannot be restarted.

o Example:

▪ After completing the execution of its run() method, the thread moves to the
terminated state and can no longer be started again.
Thread Life Cycle Flow:

Here's a visual overview of the thread life cycle:

1. New → Runnable → Blocked / Waiting / Timed Waiting → Terminated.

A thread moves through these states based on the method calls made on the thread (like start(),
sleep(), join(), wait(), etc.).

Thread Methods and Transitions in the Life Cycle:

Here are some key methods used to transition between the various states of a thread:

1. start():

o Starts the execution of a thread. A thread moves from new to runnable.

2. sleep(long millis):

o Causes the thread to sleep for a specified period, entering the timed waiting state.

3. join(long millis):

o Causes the current thread to wait until the thread it is called on has finished
executing, moving that thread to waiting.

4. wait():

o Causes the thread to wait indefinitely until it is notified by another thread.

5. notify() / notifyAll():

o These methods are used to notify one or all waiting threads that they can move back
to the runnable state.

6. interrupt():

o Interrupts a thread that is currently in the waiting, sleeping, or blocked state,


moving it to the runnable state or allowing it to terminate early if not handled.

7. isAlive():

o This method returns true if the thread is alive (i.e., it has been started and has not
yet finished), and false otherwise.

Example of Thread Life Cycle:

java

CopyEdit

class MyThread extends Thread {

public void run() {

try {
System.out.println(Thread.currentThread().getName() + " is running");

Thread.sleep(2000); // Moves to timed waiting for 2 seconds

System.out.println(Thread.currentThread().getName() + " has completed execution");

} catch (InterruptedException e) {

System.out.println(Thread.currentThread().getName() + " was interrupted");

public class ThreadLifeCycle {

public static void main(String[] args) {

MyThread t1 = new MyThread();

t1.start(); // t1 moves from 'new' to 'runnable'

try {

t1.join(); // Main thread waits for t1 to finish (t1 goes to 'waiting' state)

} catch (InterruptedException e) {

e.printStackTrace();

System.out.println("Main thread finished");

Thread Priorities in Java:

Thread priority is a way of determining the order in which threads are executed. Threads are given a
priority value between Thread.MIN_PRIORITY (1) and Thread.MAX_PRIORITY (10), with a default
value of Thread.NORM_PRIORITY (5). A higher priority thread is likely to get CPU time before lower
priority threads.

However, the actual scheduling of threads depends on the thread scheduler of the JVM and the
operating system. Therefore, thread priority is not guaranteed to ensure that high-priority threads
will always execute before low-priority threads.
Setting Thread Priority:

1. Setting a Thread's Priority:

o You can set the priority of a thread using the setPriority() method.

o This method accepts an integer value between Thread.MIN_PRIORITY (1) and


Thread.MAX_PRIORITY (10).

2. Thread Priority Constants:

o Thread.MIN_PRIORITY = 1

o Thread.NORM_PRIORITY = 5 (default)

o Thread.MAX_PRIORITY = 10

Example: Setting Thread Priorities

java

CopyEdit

class MyThread extends Thread {

public void run() {

for (int i = 0; i < 5; i++) {

System.out.println(Thread.currentThread().getName() + " Priority: " +


Thread.currentThread().getPriority() + " Value: " + i);

public class ThreadPriorityExample {

public static void main(String[] args) {

MyThread t1 = new MyThread();

MyThread t2 = new MyThread();

MyThread t3 = new MyThread();

t1.setPriority(Thread.MAX_PRIORITY); // Set max priority for t1

t2.setPriority(Thread.NORM_PRIORITY); // Default priority for t2

t3.setPriority(Thread.MIN_PRIORITY); // Set min priority for t3

t1.start(); // Start threads


t2.start();

t3.start();

Explanation of Thread Priority Example:

• t1 has the maximum priority (Thread.MAX_PRIORITY), so it is more likely to be executed


before t2 and t3.

• t2 has the default priority (Thread.NORM_PRIORITY), which is 5.

• t3 has the minimum priority (Thread.MIN_PRIORITY), so it is less likely to be executed before


the other two threads.

Inter-thread Communication in Java

Inter-thread communication is a mechanism that allows threads to communicate with each other
and synchronize their execution. Java provides a set of methods in the Object class, which all classes
inherit, to facilitate communication between threads. These methods are:

• wait()

• notify()

• notifyAll()

These methods allow threads to wait for certain conditions to be met, and notify other threads
when the condition changes, enabling synchronization between threads.

1. The wait() Method:

• wait() causes the current thread to release the lock it holds and enter the waiting state. The
thread will remain in the waiting state until it is notified by another thread.

• The thread can be notified via notify() or notifyAll() from another thread.

• The wait() method must be called from within a synchronized block or synchronized
method.

Syntax:

java

CopyEdit

public final void wait() throws InterruptedException;

2. The notify() Method:

• notify() wakes up a single thread that is waiting on the object's monitor (lock). If multiple
threads are waiting, only one of them will be notified.
• It is important to note that calling notify() does not immediately allow the waiting thread to
proceed; it simply makes it eligible to be scheduled for execution when the lock is available.

Syntax:

java

CopyEdit

public final void notify();

3. The notifyAll() Method:

• notifyAll() wakes up all the threads that are waiting on the object's monitor (lock). This
method is useful when you want to notify multiple threads waiting on the same condition.

Syntax:

java

CopyEdit

public final void notifyAll();

How It Works:

• Synchronized Block: To use wait(), notify(), or notifyAll(), you need to use synchronization.
This ensures that only one thread has access to the shared resource at any given time.

• Condition Variables: These are used to manage inter-thread communication. Threads can
wait for certain conditions to be met before proceeding.

You might also like