JavaThread Lifecycle

Thread Lifecycle

A Java thread moves through a well-defined set of states over its lifetime, represented by the enum Thread.State. Understanding these states — and what causes a thread to move between them — makes debugging concurrent code (deadlocks, stuck threads, unexpected slowdowns) far more approachable.
The Six Thread States

State

Meaning

NEW

Thread object created, but start() hasn't been called yet

RUNNABLE

Eligible to run — either currently executing or waiting for CPU time from the scheduler

BLOCKED

Waiting to acquire a lock (synchronized block/method) held by another thread

WAITING

Waiting indefinitely for another thread's action, e.g. after calling wait() or join() with no timeout

TIMED_WAITING

Waiting for a bounded amount of time, e.g. Thread.sleep(ms) or join(ms)

TERMINATED

run() has completed — the thread has finished executing and cannot be restarted

Observing state transitions

Java
public class LifecycleDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException ignored) { }
        });

        System.out.println(worker.getState()); // NEW

        worker.start();
        System.out.println(worker.getState()); // RUNNABLE

        Thread.sleep(100);
        System.out.println(worker.getState()); // TIMED_WAITING (inside sleep)

        worker.join(); // wait for it to finish
        System.out.println(worker.getState()); // TERMINATED
    }
}
NEW
RUNNABLE
TIMED_WAITING
TERMINATED
Thread.sleep() — Pausing Execution
Thread.sleep(millis) pauses the current thread for at least the given number of milliseconds, moving it into TIMED_WAITING. It doesn't release any locks the thread is holding, and it can be interrupted, which is why it declares a checked InterruptedException.
join() — Waiting for Another Thread to Finish
thread.join() blocks the calling thread until thread reaches TERMINATED. It's the standard way to make sure background work has actually completed before the main thread moves on — for example, waiting for several worker threads to finish before reading their combined results.

join() ensures work finishes before continuing

Java
Thread worker = new Thread(() -> {
    System.out.println("Worker starting");
    try {
        Thread.sleep(300);
    } catch (InterruptedException ignored) { }
    System.out.println("Worker done");
});

worker.start();
worker.join(); // main thread waits here until worker terminates
System.out.println("Main thread sees worker has finished");
Worker starting
Worker done
Main thread sees worker has finished
Note
Without the join() call, "Main thread sees worker has finished" could print before the worker even starts its sleep — start() only schedules the thread; it doesn't wait for it.
Virtual Threads — Java 21
Virtual threads (Java 21)
Java 21 introduced virtual threads as a stable feature — lightweight threads managed by the JVM rather than mapped one-to-one onto operating system threads. They go through the same conceptual lifecycle described here, but the JVM can run millions of them concurrently instead of the few thousand practical with traditional platform threads, since blocking operations no longer tie up a scarce OS thread. This is a major evolution for highly concurrent server applications — a topic worth its own dedicated deep dive beyond this introduction.
Tip
When debugging a "stuck" application, taking a thread dump and checking each thread's state is often the fastest way to spot the problem: many threads sitting in BLOCKED usually points to lock contention, while threads stuck in WAITING often means something never signaled completion.
  • Thread.State defines six states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED

  • Thread.sleep() pauses the current thread for a bounded time without releasing locks

  • join() blocks the calling thread until another thread terminates

  • Java 21's virtual threads follow the same lifecycle but scale to vastly more concurrent threads