← Back to Home

Thread Lifecycle

The Thread Lifecycle in Java describes the various states a thread goes through from creation to termination. Understanding these states is essential for multithreading, debugging, performance tuning, and interviews.

What Is Thread Lifecycle?

The thread lifecycle represents the state transitions of a thread during its execution in the JVM. Java defines thread states in the Thread.State enum.

Thread States in Java

Java has 6 official thread states:

  1. NEW
  2. RUNNABLE
  3. BLOCKED
  4. WAITING
  5. TIMED_WAITING
  6. TERMINATED

1️⃣ NEW State

  • Thread object is created
  • start() not yet called
  • Thread is not eligible for execution
Thread t = new Thread(); // NEW
          
  • ✔ Memory allocated
  • ❌ CPU not allocated

2️⃣ RUNNABLE State

  • Thread is ready to run or running
  • start() has been called
  • JVM hands over thread to OS scheduler
t.start(); // RUNNABLE
          
  • ✔ Thread may be running or waiting for CPU
  • ✔ Java combines Ready + Running into RUNNABLE

3️⃣ BLOCKED State

  • Thread is waiting to acquire a monitor lock
  • Occurs with synchronized blocks
synchronized (lock) {
    // critical section
}
          
  • ✔ Thread waits until lock is released
  • ✔ Does NOT consume CPU

4️⃣ WAITING State

  • Thread waits indefinitely for another thread’s action
  • No timeout specified

Caused by:

  • wait()
  • join()
  • park()
obj.wait();   // WAITING
          

✔ Thread resumes only when notified

5️⃣ TIMED_WAITING State

  • Thread waits for a specified amount of time

Caused by:

  • sleep(time)
  • wait(time)
  • join(time)
Thread.sleep(1000); // TIMED_WAITING
          

✔ Automatically resumes after timeout

6️⃣ TERMINATED State

  • Thread execution completed
  • run() method exits normally or due to exception
// run() method ends
          
  • ✔ Thread cannot be restarted
  • ❌ Calling start() again → IllegalThreadStateException

Thread Lifecycle Flow (Conceptual)

NEW
 ↓ start()
RUNNABLE
  ↓ lock unavailable
BLOCKED
  ↓ lock acquired
RUNNABLE
  ↓ wait()
WAITING
  ↓ notify()
RUNNABLE
  ↓ sleep(time)
TIMED_WAITING
  ↓ time expires
RUNNABLE
  ↓ run() ends
TERMINATED
          

Important Notes (Interview Traps)

  • start() → creates new call stack
  • Calling run() directly ❌ does NOT start a new thread
  • sleep() does NOT release lock
  • wait() releases lock
  • BLOCKED ≠ WAITING

Thread State vs Method Mapping

Method Resulting State
start() RUNNABLE
sleep() TIMED_WAITING
wait() WAITING
join() WAITING
synchronized lock unavailable BLOCKED
run() completes TERMINATED

Interview-Ready Answers

Short Answer

Thread lifecycle represents the various states a thread goes through during execution.

Detailed Answer

In Java, a thread goes through six states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED. These states represent thread creation, execution readiness, lock waiting, indefinite waiting, timed waiting, and completion. The JVM manages these transitions based on thread behavior and synchronization.

Key Takeaway

Threads move through well-defined states controlled by JVM and OS scheduler. Understanding thread lifecycle is critical for writing correct, efficient, and deadlock-free multithreaded programs.

Thread Lifecycle States (Reference)

  1. NEW
  2. RUNNABLE
  3. BLOCKED
  4. WAITING
  5. TIMED_WAITING
  6. TERMINATED

NEW State (Thread Created but Not Started)

class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("Run"));
        System.out.println(t.getState());
    }
}
          

Output

NEW

RUNNABLE State (After start())

class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println(Thread.currentThread().getState());
        });
        t.start();
    }
}
          

Explanation

  • Thread is ready or running
  • JVM does scheduling

IllegalStateException (Calling start() Twice)

class Demo {
    public static void main(String[] args) {
        Thread t = new Thread();
        t.start();
        // t.start(); // ❌ IllegalThreadStateException
    }
}
          

TERMINATED State (Thread Finished Execution)

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> System.out.println("Done"));
        t.start();
        t.join();
        System.out.println(t.getState());
    }
}
          

Output

TERMINATED

TIMED_WAITING Using sleep()

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {}
        });
        t.start();
        Thread.sleep(100);
        System.out.println(t.getState());
    }
}
          

Output

TIMED_WAITING

WAITING State Using join()

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(500);
            } catch (Exception e) {}
        });

        Thread t2 = new Thread(() -> {
            try {
                t1.join();
            } catch (Exception e) {}
        });

        t1.start();
        t2.start();
        Thread.sleep(100);
        System.out.println(t2.getState());
    }
}
          

Output

WAITING

WAITING Using wait()

class Demo {
    static final Object lock = new Object();

    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (Exception e) {}
            }
        });

        t.start();
        Thread.sleep(100);
        System.out.println(t.getState());
    }
}
          

Output

WAITING

BLOCKED State (Waiting for Monitor Lock)

class Demo {
    static final Object lock = new Object();

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {}
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Got Lock");
            }
        });

        t1.start();
        Thread.sleep(100);
        t2.start();
        Thread.sleep(100);

        System.out.println(t2.getState());
    }
}
          

Output

BLOCKED

Transition: NEW → RUNNABLE → TERMINATED

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> System.out.println("Work"));
        System.out.println(t.getState()); // NEW
        t.start();
        t.join();
        System.out.println(t.getState()); // TERMINATED
    }
}
          

RUNNABLE Does NOT Mean Running Always

class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {}
        });
        t.start();
        System.out.println(t.getState());
    }
}
          

Explanation

  • RUNNABLE = ready OR running

sleep() Does NOT Release Lock

class Demo {
    static final Object lock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {}
            }
        }).start();
    }
}
          

Explanation

  • Lock held during sleep()

wait() Releases Lock

class Demo {
    static final Object lock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (Exception e) {}
            }
        }).start();
    }
}
          

notify() Moves Thread to RUNNABLE

class Demo {
    static final Object lock = new Object();

    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (Exception e) {}
                System.out.println("Resumed");
            }
        });

        t.start();
        Thread.sleep(500);

        synchronized (lock) {
            lock.notify();
        }
    }
}
          

join() Causes WAITING

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(500);
            } catch (Exception e) {}
        });

        t.start();
        t.join();
        System.out.println("Main resumed");
    }
}
          

Daemon Thread Lifecycle

class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {}
        });
        t.setDaemon(true);
        t.start();
        System.out.println("Main ends");
    }
}
          

Explanation

  • JVM exits → daemon threads stop

Thread Lifecycle with Exception

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            int x = 10 / 0;
        });
        t.start();
        t.join();
        System.out.println(t.getState());
    }
}
          

Output

TERMINATED

Checking Thread State Repeatedly

class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(300);
            } catch (Exception e) {}
        });
        t.start();

        while (t.isAlive()) {
            System.out.println(t.getState());
            Thread.sleep(100);
        }
    }
}
          

Lifecycle Trap (Calling run() Directly)

class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("Thread"));
        t.run(); // ❌ No new thread
    }
}
          

Explanation

  • Executes like a normal method
  • No lifecycle change

Interview Summary – Thread Lifecycle

NEW → RUNNABLE → (WAITING / BLOCKED / TIMED_WAITING) → RUNNABLE → TERMINATED
          

Key Points

  • start() → NEW → RUNNABLE
  • sleep() → TIMED_WAITING
  • wait() / join() → WAITING
  • Lock contention → BLOCKED
  • Execution end → TERMINATED