In Java, threads are an important part of concurrent programming. A thread is an independent path of execution within a program that can perform tasks concurrently with other threads. Understanding the lifecycle of a thread in Java is crucial for writing efficient and reliable concurrent programs.
The lifecycle of a thread in Java consists of several stages, which are controlled by the Java Virtual Machine (JVM) and the thread scheduler. These stages are:
- New
- Runnable
- Running
- Waiting
- Timed Waiting
- Blocked
- Terminated
Let’s take a closer look at each stage of the lifecycle of a thread in Java.
New
The first stage of the lifecycle of a thread in Java is the New stage. In this stage, a thread is created but not yet started. To create a new thread in Java, you can extend the Thread class or implement the Runnable interface. Here’s an example of creating a new thread using the Thread class:
Thread thread = new Thread() {
public void run() {
// thread code here
}
};
In this example, we create a new Thread object and override the run() method with our thread code. However, the thread is still in the New stage and has not yet started.
Runnable
The next stage of the lifecycle of a thread in Java is the Runnable stage. In this stage, a thread is ready to run but not yet running. To start a thread and move it to the Runnable stage, you can call the start() method on the Thread object. Here’s an example:
Thread thread = new Thread() {
public void run() {
// thread code here
}
};
thread.start();
In this example, we create a new Thread object and call the start() method to start the thread. The thread is now in the Runnable stage and ready to run, but the thread scheduler has not yet selected it to run.
Running
The next stage of the lifecycle of a thread in Java is the Running stage. In this stage, a thread is actively executing code. The thread scheduler has selected the thread to run and it is currently running. Here’s an example:
Thread thread = new Thread() {
public void run() {
// thread code here
}
};
thread.start();
// do some other work here
// wait for the thread to finish
thread.join();
In this example, we create a new Thread object, start the thread, and then wait for it to finish using the join() method. The thread is now in the Running stage and executing its code.
Waiting
The next stage of the lifecycle of a thread in Java is the Waiting stage. In this stage, a thread is waiting for a certain condition to occur. To move a thread to the Waiting stage, you can call the wait() method on an object. Here’s an example:
Object lock = new Object();
Thread thread = new Thread() {
public void run() {
synchronized(lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
// do some other work here
// notify the waiting thread
synchronized(lock) {
lock.notify();
}
In this example, we create a new Thread object, synchronize on an object called lock, and then call the wait() method on the lock object. The thread is now in the Waiting stage and waiting for a notification from another thread. We then notify the waiting thread using the notify() method.
Timed Waiting
The next stage of the lifecycle of a thread in Java is the Timed Waiting stage. In this stage, a thread is waiting for a certain condition to occur, but only for a specified amount of time. To move a thread to the Timed Waiting stage, you can call the sleep() method or the wait() method with a timeout parameter. Here’s an example:
Object lock = new Object();
Thread thread = new Thread() {
public void run() {
synchronized(lock) {
try {
lock.wait(5000); // wait for 5 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
// do some other work here
// notify the waiting thread
synchronized(lock) {
lock.notify();
}
In this example, we create a new Thread object, synchronize on an object called lock, and then call the wait() method on the lock object with a timeout of 5000 milliseconds (5 seconds). The thread is now in the Timed Waiting stage and will wait for 5 seconds before continuing. We then notify the waiting thread using the notify() method.
Blocked
The next stage of the lifecycle of a thread in Java is the Blocked stage. In this stage, a thread is blocked waiting for a lock to be released. To move a thread to the Blocked stage, you can try to enter a synchronized block or method that is currently being held by another thread. Here’s an example:
Object lock = new Object();
Thread thread1 = new Thread() {
public void run() {
synchronized(lock) {
// do some work here
}
}
};
Thread thread2 = new Thread() {
public void run() {
synchronized(lock) {
// do some work here
}
}
};
thread1.start();
thread2.start();
In this example, we create two Thread objects, both of which synchronize on the same object called lock. When thread1 enters the synchronized block, it holds the lock and thread2 cannot enter the same block until thread1 releases the lock. The thread that is waiting for the lock to be released is now in the Blocked stage.
Terminated
The final stage of the lifecycle of a thread in Java is the Terminated stage. In this stage, a thread has completed its execution and has terminated. Here’s an example:
Thread thread = new Thread() {
public void run() {
// thread code here
}
};
thread.start();
// do some other work here
// wait for the thread to finish
thread.join();
if (thread.getState() == Thread.State.TERMINATED) {
System.out.println("Thread has terminated.");
}
In this example, we create a new Thread object, start the thread, wait for it to finish using the join() method, and then check its state using the getState() method. If the thread’s state is TERMINATED, we print a message indicating that the thread has terminated.
In conclusion, understanding the lifecycle of a thread in Java is crucial for writing efficient and reliable concurrent programs. By understanding the different stages of the lifecycle of a thread, you can better control the behavior of your threads and avoid common pitfalls in concurrent programming. Remember that the JVM and the thread scheduler control the lifecycle of a thread, but the behavior of a thread can also be affected by the code written by the developer.