0
Explore
0

Thread Lifecycle in Java – A Detailed Guide

Updated on August 1, 2025

In Java, multithreading allows concurrent execution of two or more parts of a program to maximize CPU utilization. A thread is the smallest unit of execution, and every thread in Java goes through several states (or stages) from its creation to completion.

Understanding the Thread Lifecycle is crucial when you’re working with multithreaded applications.

This guide will explain each lifecycle stage of a thread in Java using simple language, real-life analogies, and code examples so that even a beginner can follow along easily.

What is a Thread?

A Thread is like a worker that performs a specific task. In Java, every application has at least one thread: the main thread. When we create a new thread, it goes through several states before it finishes execution.

Lifecycle of a Thread

Java defines six states of a thread as per the Thread.State enum:

NEW -> RUNNABLE -> RUNNING -> BLOCKED / WAITING / TIMED_WAITING -> TERMINATED

Let’s now explore each state in detail.

1. NEW State

Definition:

A thread is in the NEW state when an object of the Thread class is created but the start() method has not been called yet.

Example:

Thread t = new Thread(() -> System.out.println("Hello from thread"));

At this point, t is in the NEW state.

Real-Life Analogy:

Imagine you’ve hired a worker, and he’s waiting outside your office. You haven’t given him any task yet.

2. RUNNABLE State

Definition:

When the start() method is called, the thread moves to the RUNNABLE state. It means it’s ready to run, but waiting for the CPU to assign time.

Example:

Thread t = new Thread(() -> System.out.println("Hello from thread"));
t.start(); // Now the thread is in RUNNABLE state

Note:

In older versions, “RUNNING” was included in RUNNABLE itself. But logically, it’s a transition between Runnable → Running.

3. RUNNING State

Definition:

When the thread scheduler picks a thread from the runnable pool and assigns CPU, it goes into the RUNNING state and begins executing the run() method.

Example:

This is managed by the JVM, so you can’t control exactly when the thread is running. But once CPU starts processing it, it is RUNNING.

Analogy:

The worker has been called in and started working on the task.

4. BLOCKED State

Definition:

If a thread tries to access a synchronized resource that is locked by another thread, it enters the BLOCKED state.

Example:

synchronized(obj) {
   // only one thread can access this block at a time
}

If thread A is inside the block and thread B also tries to enter, thread B goes into the BLOCKED state until thread A exits.

5. WAITING State

Definition:

A thread is in WAITING state if it is waiting indefinitely for another thread to perform a specific action.

Methods that cause this:

  • Object.wait()
  • Thread.join() (without timeout)

Example:

Thread t1 = new Thread(() -> {
    try {
        t2.join();  // t1 waits for t2 to finish
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

6. TIMED_WAITING State

Definition:

If a thread is waiting for a specified amount of time, it’s in the TIMED_WAITING state.

Methods that cause this:

  • sleep(time)
  • join(time)
  • wait(time)
  • Thread.sleep(1000) — puts the thread in TIMED_WAITING for 1 second.

Analogy:

The worker is taking a break for 15 minutes (you know how long he’ll rest).

7. TERMINATED (or DEAD) State

Definition:

When the thread finishes execution (either normally or due to an exception), it enters the TERMINATED state.

Example:

Thread t = new Thread(() -> System.out.println("Done"));
t.start();
// After execution, t is TERMINATED

Analogy:

The worker has finished the task and left.

Full Lifecycle Flow Diagram (Text Version)

NEW
 ↓  start()
RUNNABLE
 ↓  (picked by scheduler)
RUNNING
 ↙     ↓         ↘
BLOCKED WAITING TIMED_WAITING
       ↓           ↓
      RUNNABLE     RUNNABLE
           ↓
       TERMINATED

Complete Code Example to Observe Lifecycle Transitions

public class ThreadLifecycleDemo extends Thread {
    public void run() {
        System.out.println("Thread is RUNNING");
        try {
            Thread.sleep(2000); // TIMED_WAITING
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread is about to TERMINATE");
    }

    public static void main(String[] args) {
        ThreadLifecycleDemo t = new ThreadLifecycleDemo();

        System.out.println("Thread State after creation: " + t.getState()); // NEW
        t.start();
        System.out.println("Thread State after calling start(): " + t.getState()); // RUNNABLE

        try {
            Thread.sleep(100); // Main thread sleeps a bit to let child thread enter TIMED_WAITING
            System.out.println("Thread State during sleep: " + t.getState()); // TIMED_WAITING or RUNNABLE
            t.join(); // WAITING (main waits for t to finish)
            System.out.println("Thread State after join: " + t.getState()); // TERMINATED
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Output

Thread State after creation: NEW
Thread is RUNNING
Thread State after calling start(): RUNNABLE
Thread State during sleep: TIMED_WAITING
Thread is about to TERMINATE
Thread State after join: TERMINATED

Step-by-Step Explanation

ThreadLifecycleDemo t = new ThreadLifecycleDemo();

  • Creates a new thread object, but the thread has not started yet.
  • State: NEW
System.out.println("Thread State after creation: " + t.getState());

t.start();

  • Starts the thread — it enters the RUNNABLE state.
  • It may or may not begin executing immediately.
  • State: RUNNABLE
System.out.println("Thread State after calling start(): " + t.getState());

Inside run():

System.out.println("Thread is RUNNING");
Thread.sleep(2000);
  • The thread begins executing and prints “Thread is RUNNING”.
  • Then it calls sleep(2000), which puts it into the TIMED_WAITING state for 2 seconds.

Back in main() thread:

Thread.sleep(100);
System.out.println("Thread State during sleep: " + t.getState());
  • The main thread pauses for 100ms, during which the child thread is most likely sleeping.
  • So the state of the thread should be TIMED_WAITING.
  • If sleep finishes early (very unlikely in 100ms), it might be back to RUNNABLE.

t.join();

  • The main thread waits for the child thread to finish using join().
  • While the main thread is waiting, it enters WAITING state (though not visible here, since we check the state of t not main).
  • Once the child thread finishes, control resumes.

After thread completes:

System.out.println("Thread State after join: " + t.getState());
  • Since the thread has completed its run() method, it enters the TERMINATED state.

Summary Table

StateTriggerMeaning
NEWThread createdNot started yet
RUNNABLE.start() calledWaiting for CPU
RUNNINGGot CPU timeExecuting run() method
BLOCKEDWaiting for a lockLocked resource not available
WAITING.wait(), .join()Waiting indefinitely
TIMED_WAITINGsleep(), wait(ms), join(ms)Waiting for a specific time
TERMINATEDExecution completedThread is dead

Bonus Tip: Use Thread.getState() to Monitor Threads

You can call .getState() on any thread object to find out its current lifecycle state. This is helpful during debugging multithreaded applications.

Final Thoughts

Understanding the Thread Lifecycle in Java is a foundational step toward mastering concurrency and multithreading. It helps you control, manage, and debug complex multithreaded applications.

Now that you know how threads move between different states.