Thread Life Cycle in Java – Thread States and Transitions
Every Java thread passes through a series of states from the moment it is created until it finishes. Understanding this life cycle helps you reason about what a thread is doing, read thread dumps, and diagnose problems such as deadlocks and threads that never finish.
Java defines six states in the Thread.State enum: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING and TERMINATED. This tutorial explains each one and the transitions between them, and shows every state in a runnable program.
1. Thread States at a Glance
| State | Meaning | Entered by |
|---|---|---|
NEW | Created but not started | new Thread(...) |
RUNNABLE | Running, or ready to run and waiting for CPU time | start(); leaving any waiting state |
BLOCKED | Waiting to acquire a monitor lock | Entering a synchronized block or method held by another thread |
WAITING | Waiting indefinitely for another thread | wait(), join(), LockSupport.park() |
TIMED_WAITING | Waiting for at most a given time | sleep(ms), wait(ms), join(ms), parkNanos |
TERMINATED | Finished | run() returns or throws an exception |
2. The Six States in Detail
1. NEW
A Thread object exists, but no operating-system thread has been created yet. The only useful action is start().
2. RUNNABLE
After start(), the thread is eligible to run. Java does not distinguish "ready" from "running": both are RUNNABLE, and the OS scheduler decides which runnable thread uses a CPU core. A thread blocked in native I/O, such as reading a socket, is also reported as RUNNABLE.
3. BLOCKED
The thread wants to enter a synchronized block or method, but another thread holds the monitor. It becomes RUNNABLE again when it acquires the lock. (Threads waiting on java.util.concurrent locks appear as WAITING instead.)
4. WAITING
The thread waits with no time limit for another thread to act: a notify()/notifyAll() after wait(), the end of a thread it join()ed, or an unpark().
5. TIMED_WAITING
Like WAITING, but it returns to RUNNABLE automatically when the timeout expires. Thread.sleep() is the most common cause.
6. TERMINATED
The run() method has completed, normally or with an uncaught exception. A terminated thread cannot be restarted.
3. Observing Every State
getState() returns a thread's current state. This program drives threads through all six states:
public class ThreadStates {
static final Object lock = new Object();
static void waitUntil(Thread t, Thread.State s) throws InterruptedException {
while (t.getState() != s) Thread.sleep(5);
}
public static void main(String[] args) throws InterruptedException {
// NEW -> RUNNABLE -> TIMED_WAITING -> TERMINATED
Thread sleeper = new Thread(() -> {
long end = System.nanoTime() + 100_000_000;
while (System.nanoTime() < end) { } // busy for 100 ms: RUNNABLE
try { Thread.sleep(300); } catch (InterruptedException e) { } // TIMED_WAITING
});
System.out.println("After new: " + sleeper.getState());
sleeper.start();
System.out.println("After start(): " + sleeper.getState());
waitUntil(sleeper, Thread.State.TIMED_WAITING);
System.out.println("In sleep(): " + sleeper.getState());
sleeper.join();
System.out.println("After finish: " + sleeper.getState());
// BLOCKED: waiting to enter a synchronized block held by main
Thread blocked = new Thread(() -> { synchronized (lock) { } });
synchronized (lock) {
blocked.start();
waitUntil(blocked, Thread.State.BLOCKED);
System.out.println("Lock held: " + blocked.getState());
}
blocked.join();
// WAITING: wait() with no timeout until notify()
Thread waiter = new Thread(() -> {
synchronized (lock) {
try { lock.wait(); } catch (InterruptedException e) { }
}
});
waiter.start();
waitUntil(waiter, Thread.State.WAITING);
System.out.println("In wait(): " + waiter.getState());
synchronized (lock) { lock.notify(); }
waiter.join();
System.out.println("After notify(): " + waiter.getState());
}
}
After new: NEW After start(): RUNNABLE In sleep(): TIMED_WAITING After finish: TERMINATED Lock held: BLOCKED In wait(): WAITING After notify(): TERMINATED
getState() is designed for monitoring and debugging, not for synchronization; the state may change immediately after you read it.
4. A Thread Cannot Be Started Twice
public class StartTwice {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> System.out.println("Running once"));
t.start();
t.join();
try {
t.start(); // a TERMINATED thread cannot be restarted
} catch (IllegalThreadStateException e) {
System.out.println("Second start(): " + e.getClass().getSimpleName());
}
}
}
Running once Second start(): IllegalThreadStateException
To run the same work again, create a new Thread, or better, submit the task to a thread pool.
5. Interrupting a Waiting Thread
interrupt() asks a thread to stop what it is doing. A thread in sleep, wait or join wakes up with an InterruptedException; a running thread can check Thread.currentThread().isInterrupted():
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
try {
System.out.println("Worker: sleeping for 10 seconds");
Thread.sleep(10_000);
System.out.println("Worker: woke up normally");
} catch (InterruptedException e) {
System.out.println("Worker: interrupted, cleaning up and exiting");
}
});
worker.start();
Thread.sleep(200);
worker.interrupt(); // TIMED_WAITING -> RUNNABLE (via InterruptedException)
worker.join();
System.out.println("Main: worker state = " + worker.getState());
}
}
Worker: sleeping for 10 seconds Worker: interrupted, cleaning up and exiting Main: worker state = TERMINATED
6. Methods That Change State
| Method | Transition |
|---|---|
start() | NEW → RUNNABLE |
Thread.sleep(ms) | RUNNABLE → TIMED_WAITING → RUNNABLE |
wait() / notify() | RUNNABLE → WAITING → BLOCKED (reacquiring the lock) → RUNNABLE |
join() | RUNNABLE → WAITING until the other thread terminates |
synchronized entry | RUNNABLE → BLOCKED while the lock is busy |
Thread.yield() | Stays RUNNABLE; only hints that others may run |
interrupt() | Wakes a WAITING / TIMED_WAITING thread with an exception |
The old methods stop(), suspend() and resume() are deprecated and unsafe (and stop() now always throws). Use interruption or a volatile flag instead.
7. Summary
- A Java thread is in one of six states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING or TERMINATED.
- RUNNABLE covers both running and ready-to-run.
- BLOCKED is about monitor locks; WAITING and TIMED_WAITING are about waiting for other threads or time.
- A terminated thread cannot be restarted; use
interrupt()to request a stop.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What are the states of a thread in Java?
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING and TERMINATED, defined in the Thread.State enum.
Q2. Is there a RUNNING state in Java?
No. Both running and ready-to-run threads are reported as RUNNABLE; the operating system decides which actually executes.
Q3. What is the difference between BLOCKED and WAITING?
BLOCKED means waiting to acquire a monitor lock. WAITING means waiting for another thread's action, such as notify() or the end of a joined thread.
Q4. What is the difference between WAITING and TIMED_WAITING?
WAITING has no time limit. TIMED_WAITING returns automatically after the specified time, as with sleep(ms) or wait(ms).
Q5. Which state is a thread in during sleep()?
TIMED_WAITING.
Q6. Can a terminated thread be restarted?
No. Calling start() again throws IllegalThreadStateException.
Q7. How do I get the state of a thread?
Call thread.getState(), which returns a Thread.State value.
Q8. Does sleep() release a lock?
No. A sleeping thread keeps any monitors it holds. wait(), by contrast, releases the monitor while waiting.
Q9. What happens when notify() is called?
One waiting thread wakes up and moves to BLOCKED until it can reacquire the monitor, then continues as RUNNABLE.
Q10. Which state is a thread in during join()?
WAITING for join(), or TIMED_WAITING for join(ms).
Q11. What is the state of a thread blocked on socket I/O?
RUNNABLE. The JVM does not track native I/O waits as a separate state.
Q12. What does yield() do?
It hints to the scheduler that the current thread is willing to give up the CPU. The thread stays RUNNABLE, and the hint may be ignored.
Q13. How does a thread reach TERMINATED?
When its run() method returns normally or ends with an uncaught exception.
Q14. Why are stop(), suspend() and resume() deprecated?
They can leave objects in inconsistent states or cause deadlocks. Use interruption and cooperative stopping instead.
Q15. What does interrupt() do?
It sets the thread's interrupt flag. If the thread is sleeping, waiting or joining, it wakes with an InterruptedException.
Q16. Which state do threads waiting on ReentrantLock show?
WAITING or TIMED_WAITING, because java.util.concurrent locks park threads with LockSupport rather than using monitors.
Q17. How can I see thread states in a running application?
Take a thread dump with jstack <pid>, jcmd <pid> Thread.print, VisualVM or JDK Mission Control.
Q18. Do virtual threads have the same states?
Yes. They report the same Thread.State values, although a blocked virtual thread usually releases its carrier thread.
Q19. Can a thread go from NEW directly to TERMINATED?
Not without being started. After start(), a very short task may finish so quickly that you only ever observe TERMINATED.
Q20. Is the thread life cycle the same as the process life cycle?
No. Java thread states are defined by the JVM and differ from operating-system process states, although they map loosely to ready, running and waiting.