Concurrency
Threads & Their Lifecycle
A
Thread executes a Runnable concurrently with the rest of the program. Threads are the unit of scheduling; understanding their states — and interruption, the cooperative stop mechanism — underlies everything else in concurrency.- Start with
Thread.ofPlatform().start(task)/new Thread(task).start()— never callrun()directly - States: NEW → RUNNABLE ⇄ (BLOCKED | WAITING | TIMED_WAITING) → TERMINATED
- Interruption is cooperative:
interrupt()sets a flag; the target must check or be blocked InterruptedExceptionclears the flag — restore it or rethrow, never swallow- Daemon threads don't keep the JVM alive
- In application code, prefer executors over raw threads (EJ 80)
Thread worker = Thread.ofPlatform().name("loader").start(() -> load(data));
// … do other work …
worker.join(); // wait for completion
Thread vt = Thread.ofVirtual().start(() -> fetch(url)); // virtual: cheap, see Virtual ThreadsCalling run() executes the task on your thread — the classic beginner bug; start() is what creates the new one. A thread terminates when its run method returns or throws; an uncaught exception kills only that thread (install an UncaughtExceptionHandler to at least log it — silent thread death is a notorious production mystery).
| State | Meaning | Typical cause |
|---|---|---|
| NEW | created, not started | before start() |
| RUNNABLE | running or ready to run | normal execution |
| BLOCKED | waiting for a monitor lock | contended synchronized |
| WAITING | parked indefinitely | join(), wait(), park() |
| TIMED_WAITING | parked with a deadline | sleep(ms), join(ms), wait(ms) |
| TERMINATED | run() finished | completion or uncaught exception |
Interruption — the only sane way to stop
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
process(queue.take()); // blocking calls throw InterruptedException
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore the flag for callers up-stack
}
}