What are the six thread states defined by Java's Thread.State enum, and what does each one mean?
answer
- Six states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
- RUNNABLE merges running + ready (and I/O-wait)
- BLOCKED = monitor lock; WAITING = wait/join/park; TIMED = +timeout
- getState() is diagnostic only, never for control flow
- TERMINATED is final — can't restart
basics
~20 sA Java thread is in one of six states: NEW (created, not started), RUNNABLE (running or ready to run), BLOCKED (waiting for a lock), WAITING (waiting indefinitely for another thread), TIMED_WAITING (waiting with a timeout), and TERMINATED (finished).
solid answer
~40 sJava models a thread's life with the Thread.State enum, which has exactly six values. NEW means the Thread object exists but start() hasn't been called. RUNNABLE means the thread is executing or eligible to execute (Java doesn't distinguish 'ready' from 'running'; the OS scheduler decides). BLOCKED means it's waiting to acquire a monitor lock to enter a synchronized block. WAITING means it waits indefinitely for another thread to act, via Object.wait(), Thread.join(), or LockSupport.park() with no timeout. TIMED_WAITING is the same but with a deadline, from sleep(ms), wait(ms), join(ms), or parkNanos. TERMINATED means run() has completed or thrown. You read a thread's state with getState(), mainly for diagnostics, never for control flow.
go deeper
Can list the six states and give a one-line meaning for each, and knows getState() returns them.
Correctly distinguishes BLOCKED vs WAITING vs TIMED_WAITING and knows RUNNABLE covers I/O-wait.
Explains the monitor re-acquisition subtlety after wait(), why RUNNABLE merges ready/running, and uses states to read thread dumps for diagnosis.
Frames getState() as inherently racy/diagnostic, reasons about how these map (or don't) to OS scheduler states, and uses thread-dump state analysis to drive concurrency design and incident triage.
## What a thread is A **thread** is an independent path of execution within a process: it has its own call stack and program counter but shares heap memory with other threads in the same JVM. In Java a thread is represented by a `java.lang.Thread` object. ## Why states exist A thread does not run continuously from birth to death. It is created, may run, may pause to wait for something (a lock, a timeout, a signal from another thread), and eventually finishes. To make this observable, Java defines an enum `Thread.State` with **exactly six** values. You query it with `thread.getState()`. This is a *diagnostic* view — it reflects what the thread is doing at the instant you ask. ## The six states, defined from scratch 1. **NEW** — The `Thread` object has been constructed (e.g. `new Thread(r)`) but `start()` has not been called yet. No OS-level thread exists; nothing is executing. 2. **RUNNABLE** — `start()` has been called. The thread is either actually running on a CPU core *or* sitting in the OS run queue waiting for a core. **Java deliberately merges 'running' and 'ready-to-run' into one state**, because from the JVM's point of view the OS scheduler owns that distinction. Importantly, a thread blocked on I/O (e.g. a socket read) is *still* RUNNABLE in Java's model — Java has no separate I/O-wait state. 3. **BLOCKED** — The thread is trying to enter a `synchronized` block or method but another thread holds that object's **monitor lock**. A monitor is the intrinsic lock every Java object carries. The thread parks here until the lock is released and it wins it. BLOCKED is *specifically* about monitor-lock contention. 4. **WAITING** — The thread is waiting **indefinitely** for an explicit action by another thread, with no timeout. You reach WAITING by calling `Object.wait()` (no args), `Thread.join()` (no args), or `LockSupport.park()`. It leaves WAITING only when another thread does the matching thing: `notify()`/`notifyAll()`, the joined thread terminating, or `unpark()`. 5. **TIMED_WAITING** — Same idea as WAITING, but bounded by a **timeout**. You reach it via `Thread.sleep(ms)`, `Object.wait(ms)`, `Thread.join(ms)`, `LockSupport.parkNanos`, or `parkUntil`. The thread leaves when it's signalled *or* when the deadline expires — whichever comes first. 6. **TERMINATED** — The thread's `run()` method has returned normally or propagated an exception. The thread is dead; it cannot be restarted (calling `start()` again throws `IllegalThreadStateException`). ## The key distinctions interviewers probe - **BLOCKED vs WAITING**: BLOCKED is *involuntary* contention for a monitor lock to enter `synchronized`. WAITING is *voluntary* — the thread called `wait()`/`join()`/`park()` and gave up the CPU until told otherwise. (Subtle: a thread that returns from `wait()` must *re-acquire* the monitor, so it can briefly pass through BLOCKED before becoming RUNNABLE.) - **WAITING vs TIMED_WAITING**: the only difference is whether a timeout was supplied. - **RUNNABLE is broad**: includes running, scheduler-ready, and blocked-on-I/O. ## How to observe it `Thread.getState()` returns the enum. Tools like `jstack` and thread dumps print these states, which is how you diagnose deadlocks (threads stuck in BLOCKED) or stuck waits (threads in WAITING). ## What NOT to do Never branch program logic on `getState()` — the value can change the instant after you read it (it is inherently racy). Use proper synchronization primitives instead.
- Why does Java not have a distinct RUNNING state?Because whether a RUNNABLE thread is actually on a CPU or just queued is decided by the OS scheduler, which the JVM doesn't control or reliably observe. Merging them keeps the model portable across schedulers.
- Can a TERMINATED thread be restarted?No. Calling start() on a thread that already ran throws IllegalThreadStateException. You must create a new Thread object.
saying these in an interview costs you the question
- Saying there is a separate 'RUNNING' state distinct from RUNNABLE — Java has none.
- Claiming a thread blocked on I/O is in BLOCKED — it's RUNNABLE.
- Confusing BLOCKED (monitor contention) with WAITING (voluntary wait/join/park).
- Thinking sleep() puts a thread in WAITING — it's TIMED_WAITING.