Thread Life Cycle In Java

Java threads transition through various unique phases throughout their existence, as outlined within the java.lang.Thread.State category. Each thread state is represented by an Enum constant, with a thread capable of occupying just a single state at any particular moment.

The states referred to here are those specific to virtual machines and do not mirror the states of any operating system threads. A thread within a system can exist in any of the subsequent states:

Thread States Description
NEW A thread that has not yet started is in this state.
RUNNABLE A thread executing in the Java virtual machine is in this state.
BLOCKED A thread that is blocked waiting for a monitor lock is in this state.
WAITING A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
TIMED_WAITING A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
TERMINATED A thread that has exited is in this state.

Thread States

A thread is considered to be in the "NEW" state when a Thread object is instantiated but the start method has not been called yet. During this phase, the thread is dormant and is not ready to be executed by the thread scheduler.

Example

public static final Thread.State NEW

A RUNNABLE thread is one that is prepared to execute and triggers the start function, transitioning from the NEW state to the RUNNABLE state. During the RUNNABLE state, the thread can either be actively executing or awaiting its turn to run at any specific moment. The responsibility lies with the thread scheduler to allocate time for the thread to execute.

Example

public static final Thread.State RUNNABLE

In a multithreading program, each thread is allocated a specific time quantum to execute. Threads run for a brief period and then yield the CPU voluntarily once their time quantum is complete. This allows other threads to also run for their allocated time. When threads are waiting for their turn to run in this manner, they are in the RUNNABLE state. The RUNNABLE state consists of a queue where these threads are positioned.

When a thread gains control of the CPU, it transitions from the RUNNABLE state to the running state. Typically, the most frequent transition for a thread involves moving from the RUNNABLE state to running and then back to RUNNABLE.

When a thread is unable to acquire a monitor lock that is currently held by another thread, it transitions into the BLOCKED state. This situation commonly arises when a thread is trying to access a synchronized block or method but is unable to do so due to the lock being held by another thread.

Example

public static final Thread.State BLOCKED

Consider a scenario where one thread, referred to as A, requires the printer to output data. Simultaneously, another thread, named B, is utilizing the printer for a printing task. Consequently, thread A must wait for thread B to finish its printing operation before it can access the printer. As a result, thread A becomes blocked, indicating its inability to execute any operations and consequently not utilizing any CPU cycles. Consequently, thread A remains inactive until the thread scheduler reactivates it from the waiting or blocked state for further processing.

Once the primary thread calls the join method, it transitions into the WAITING state, where it patiently awaits the child threads to finish their respective tasks. As soon as the child threads are done with their execution, a signal is relayed to the main thread, prompting its transition from the WAITING state back to the RUNNABLE state.

When numerous threads are in a state of waiting or being blocked, the responsibility falls on the thread scheduler to decide on the selection and rejection of threads. The selected thread is granted the chance to execute in such scenarios.

A thread enters the Waiting state when it needs to wait indefinitely for another thread to complete a specific action. This situation arises when methods such as Object.wait (without a timeout) or Thread.join (without a timeout) are utilized. The thread will stay in the Waiting state until it receives a notification from another thread (e.g., through Object.notify or Object.notifyAll) or until the joined thread finishes its task.

Example

public static final Thread.State WAITING

The key difference between WAITING and TIMED_WAITING is the time constraint. Waiting has no time constraint, whereas timed waiting has the time constraint. A thread invoking the following method reaches the timed waiting state.

  • sleep
  • join with timeout
  • wait with timeout
  • parkUntil
  • parkNanos

It denotes the conclusive status of a thread that has been terminated or is no longer active. When a thread is terminated, it signifies that the thread has finished its execution.

When it comes to waiting causing starvation, a situation can arise where one thread (referred to as A) occupies a critical section of a code and refuses to exit. This can result in another thread (referred to as B) waiting indefinitely, leading to starvation. To prevent this, a timed waiting state is introduced for thread B. This means that thread B remains in a waiting state for a defined period of time rather than indefinitely. An illustration of timed waiting is when the sleep method is utilized on a specific thread. By invoking the sleep method, the thread is placed in a TIMED_WAIT state. Once the specified time elapses, the thread awakens and continues its execution from where it paused earlier.

Example

public static final Thread.State TIMED_WAITING

A thread transitions to the TERMINATED state due to the following circumstances:

  • Normal termination takes place when a thread completes its task and exits gracefully.
  • Abnormal termination arises from exceptional occurrences like an uncaught exception or a segmentation fault.

When a thread is terminated, it is no longer present in the system, effectively rendering it inactive. Once a thread is terminated, it cannot be revived or brought back to an active state.

Example

public static final Thread.State TERMINATED

The diagram below illustrates the various states that a thread goes through during its life cycle.

Transitions Between States

  • new → start → runnable
  • runnable → scheduler picks → running
  • running → wait/join → waiting
  • running → sleep/join(timeout) → timed waiting
  • running → blocked → when trying to acquire a lock
  • any state → finished/error → terminated
  • Example: Thread States

The Java program below demonstrates various states of a thread that has been defined earlier.

Example

Example

// ABC class implements the interface Runnable  

class ABC implements Runnable {

	public void run() {

// try-catch block  

		try {

// moving thread t2 to the state timed waiting  

			Thread.sleep(100);

		} catch (InterruptedException ie) {

			ie.printStackTrace();

		}

		System.out.println(

				"The state of thread t1 while it invoked the method join() on thread t2 -" + Main.t1.getState());

// try-catch block  

		try {

			Thread.sleep(200);

		} catch (InterruptedException ie) {

			ie.printStackTrace();

		}

	}

}

// Thread.State class implements the interface Runnable  

public class Main implements Runnable {

	public static Thread t1;

	public static Main obj;

// main method   

	public static void main(String argvs[]) {

// creating an object of the class Thread.State  

		obj = new Main();

		t1 = new Thread(obj);

// thread t1 is spawned   

// The thread t1 is currently in the NEW state.  

		System.out.println("The state of thread t1 after spawning it - " + t1.getState());

// invoking the start() method on   

// the thread t1  

		t1.start();

// thread t1 is moved to the Runnable state  

		System.out.println("The state of thread t1 after invoking the method start() on it - " + t1.getState());

	}

	public void run() {

		ABC myObj = new ABC();

		Thread t2 = new Thread(myObj);

// thread t2 is created and is currently in the NEW state.  

		System.out.println("The state of thread t2 after spawning it - " + t2.getState());

		t2.start();

// thread t2 is moved to the runnable state  

		System.out.println("the state of thread t2 after calling the method start() on it - " + t2.getState());

// try-catch block for the smooth flow of the  program  

		try {

// moving the thread t1 to the state timed waiting   

			Thread.sleep(200);

		} catch (InterruptedException ie) {

			ie.printStackTrace();

		}

		System.out.println("The state of thread t2 after invoking the method sleep() on it - " + t2.getState());

// try-catch block for the smooth flow of the program  

		try {

// waiting for thread t2 to complete its execution  

			t2.join();

		} catch (InterruptedException ie) {

			ie.printStackTrace();

		}

		System.out.println("The state of thread t2 when it has completed it's execution - " + t2.getState());

	}

}

Output:

Output

The state of thread t1 after spawning it - NEW

The state of thread t1 after invoking the method start() on it - RUNNABLE

The state of thread t2 after spawning it - NEW

the state of thread t2 after calling the method start() on it - RUNNABLE

The state of thread t1 while it invoked the method join() on thread t2 -TIMED_WAITING

The state of thread t2 after invoking the method sleep() on it - TIMED_WAITING

The state of thread t2 when it has completed it's execution - TERMINATED

When a new thread is created, it enters a new state. By calling the start method on a thread, the thread scheduler transitions it to the runnable state. If the join method is called on a thread instance, the current thread must wait for that thread to complete its execution, moving it to the terminated state.

In the scenario provided, before the final print statement is displayed on the console, the program calls the join method on thread t2. This action causes thread t1 to pause execution until thread t2 finishes its task and reaches the terminated state. Consequently, thread t1 is in a waiting state as it is dependent on thread t2 to complete its task due to the invocation of the join method on thread t2.

Life cycle of a Thread MCQ

  1. Which method can be used to interrupt a thread that is in the TIMED_WAITING or WAITING state, causing it to transition to the RUNNABLE state?
  • notify
  • interrupt
  • join
  • start

Explanation: The interrupt method can be used to interrupt a thread that is in the TIMED_WAITING or WAITING state, causing it to transition to the RUNNABLE state by throwing an InterruptedException.

  1. Which of the following methods can be used to make a currently running thread yield execution to another thread of the same or higher priority?
  • sleep
  • yield
  • wait
  • notify

Explanation: The yield method is used to make the currently running thread pause and allow other threads of the same or higher priority to execute.

  1. What happens to a thread if it calls the join method on another thread?
  • It enters the BLOCKED state
  • It enters the WAITING state until the other thread completes
  • It enters the TIMED_WAITING state for a fixed time
  • It continues running without any change in state

Explanation: When a thread calls the join method on another thread, it enters the WAITING state until the other thread completes its execution.

  1. Which method is used to request a thread to stop its execution and can be safely ignored by the thread?
  • stop
  • suspend
  • interrupt
  • terminate

Explanation: The interrupt method requests a thread to stop its execution, but the thread can safely ignore it if it is not designed to handle interruptions.

  1. When a thread has acquired a lock on an object, which state does it enter if another thread attempts to acquire the same lock?
  • TIMED_WAITING
  • WAITING
  • BLOCKED
  • RUNNABLE

When a thread successfully obtains a lock on an object, any other thread trying to acquire the same lock will be in a state of being BLOCKED until the lock is freed.

Input Required

This code uses input(). Please provide values below: