Thread Lifecycle in Java Explained: States, Transitions, and Best Practices

Illustration for Thread Lifecycle in Java Explained: States, Transitions, and Best Practices
By Last updated:

In Java's multithreaded world, understanding the lifecycle of a thread is fundamental for building reliable and high-performance applications. Each thread in Java transitions through several well-defined states, and knowing when and how these transitions occur is key to writing correct concurrent programs.

This guide walks you through the entire thread lifecycle, best practices, coordination techniques, and the evolving landscape with Java 8–21.


What is a Thread?

A thread is the smallest unit of execution within a Java program. Java supports multithreading via the Thread class and Runnable/Callable interfaces, enabling developers to execute multiple parts of a program concurrently.


Thread Lifecycle: The 6 States

NEW → RUNNABLE → BLOCKED/WAITING/TIMED_WAITING → TERMINATED

1. NEW

  • Thread is created but not started.
Thread t = new Thread(() -> {});

2. RUNNABLE

  • Thread is ready to run and waiting for CPU time.
t.start();

3. BLOCKED

  • Thread is waiting to acquire a lock.

4. WAITING

  • Thread waits indefinitely for another thread to perform an action.

5. TIMED_WAITING

  • Thread waits for a specific time using:
    • sleep(ms)
    • join(ms)
    • wait(ms)

6. TERMINATED

  • Thread has completed execution or was aborted.

Lifecycle Transitions with Example

Thread t = new Thread(() -> {
    try {
        Thread.sleep(1000); // TIMED_WAITING
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
});
t.start(); // RUNNABLE

Coordination Tools in Lifecycle

  • wait(), notify(), notifyAll()
  • join() to pause until another thread finishes
  • sleep() to pause execution

Visibility and Memory

  • Java Memory Model governs how threads see shared variables
  • volatile ensures changes are visible across threads
  • synchronized also flushes memory to maintain consistency

Synchronization & Locks

  • synchronized blocks
  • ReentrantLock, ReadWriteLock, StampedLock for advanced locking
  • Avoid nested locks to prevent deadlocks

java.util.concurrent Utilities

  • ExecutorService manages thread pools
  • Future, CompletableFuture handle asynchronous computation
  • BlockingQueue, ConcurrentHashMap for thread-safe data structures

Real-World Applications

  • Producer-Consumer: Uses BlockingQueue to share data between threads
  • File Processing: Thread pool handles large files in parallel
  • Scheduling: Use ScheduledExecutorService for timed tasks

Thread Lifecycle and Java Versions

📌 What's New in Java Versions?

Java 8

  • Lambdas simplify thread creation
  • CompletableFuture for async programming

Java 9

  • Flow API for reactive programming

Java 11+

  • Enhancements to CompletableFuture

Java 21

  • Virtual Threads (Project Loom)
  • Structured Concurrency
  • Scoped Values for shared data management

Best Practices

  • Always use start() not run() directly
  • Avoid long blocking in threads; use timeouts
  • Use ExecutorService for pooling
  • Prefer higher-level abstractions like CompletableFuture

Common Pitfalls

  • Not handling InterruptedException
  • Race conditions on shared variables
  • Holding locks for too long
  • Deadlocks from improper lock ordering

  • Worker Thread: Reuses threads to perform jobs
  • Future Task: Asynchronous execution with result
  • Thread-per-Message: New thread per client request
  • Producer-Consumer: Coordination of job producers and consumers

Conclusion and Key Takeaways

  • A thread in Java goes through six distinct states
  • Knowing how and when these transitions happen prevents bugs
  • Always use thread-safe communication and lock handling
  • Adopt Java 21’s structured concurrency and virtual threads for modern scalability

FAQs

Q1: What is the difference between WAITING and TIMED_WAITING?
A: WAITING is indefinite; TIMED_WAITING waits with a timeout.

Q2: Can a thread go from BLOCKED to WAITING?
A: No, those are distinct paths; BLOCKED waits for a lock, WAITING for a condition.

Q3: What triggers the TERMINATED state?
A: The thread finishes execution or is terminated due to error.

Q4: How to debug a stuck thread?
A: Use jstack or VisualVM to analyze thread dump.

Q5: Is calling run() instead of start() safe?
A: It’s not unsafe, but it won’t create a new thread—just runs in current one.

Q6: How to restart a thread?
A: You can’t restart a thread once terminated; create a new instance.

Q7: Why is volatile not enough for atomicity?
A: It guarantees visibility, not atomic operations.

Q8: Are virtual threads in Java 21 always in RUNNABLE state?
A: No, they follow the same states but are cheaper and more scalable.

Q9: What is a daemon thread?
A: Background thread that doesn’t prevent JVM from exiting.

Q10: Can thread states be monitored at runtime?
A: Yes, using Thread.getState() or profiling tools.