Navigation
Java Full Course: Mastering the Language Thread Life Cycle in Java
Thread Life Cycle in Java
1. Introduction
A thread in Java goes through several states during its lifetime. The java.lang.Thread class defines a State enumeration that represents these states. Understanding the life cycle is crucial for writing correct, efficient, and deadlock‑free concurrent programs.
The thread life cycle consists of the following six states:
- NEW
- RUNNABLE
- BLOCKED
- WAITING
- TIMED_WAITING
- TERMINATED
A thread can transition from one state to another based on method calls (e.g., start(), sleep(), wait(), notify(), join(), etc.) and system scheduling.
2. The Six States Explained
a) NEW (Newly Created)
- A thread is in the NEW state after it has been created (using
new Thread(...)) but beforestart()is called. - At this point, the thread object exists but has not yet started execution.
b) RUNNABLE
- When the
start()method is called, the thread moves to the RUNNABLE state. - In this state, the thread is ready to run and is waiting for CPU time. The thread may be actually running or waiting for its turn to run.
- The RUNNABLE state includes both "ready to run" and "running" in the operating system's thread scheduler view.
- The JVM does not provide a separate state for "running"; it’s considered part of RUNNABLE.
c) BLOCKED
- A thread enters the BLOCKED state when it attempts to acquire a lock (enter a synchronized block/method) that is currently held by another thread.
- It remains blocked until the lock becomes available, at which point it becomes runnable again.
d) WAITING
- A thread enters the WAITING state when it is waiting indefinitely for another thread to perform a specific action.
- The transition to WAITING occurs when:
Object.wait()without timeout is called.Thread.join()without timeout is called.LockSupport.park()is called.
- The thread will leave the WAITING state when another thread calls
notify()/notifyAll()on the same object, or when the joined thread terminates, or whenunpark()is called.
e) TIMED_WAITING
- A thread enters the TIMED_WAITING state when it is waiting for a specific amount of time.
- Transitions to TIMED_WAITING occur when:
Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos(long nanos)orparkUntil(long deadline)
- After the time elapses or if it is notified/joined, the thread returns to RUNNABLE.
f) TERMINATED (Dead)
- A thread enters the TERMINATED state when it has finished execution (the
run()method completes normally or abruptly due to an exception). - Once terminated, the thread cannot be restarted (calling
start()again throwsIllegalThreadStateException).
3. State Transition Diagram
Below is a textual representation of the thread state transitions:
[!IMPORTANT]
BLOCKED and WAITING/TIMED_WAITING are distinct. BLOCKED is about lock contention, whereas WAITING is about explicit waiting for another thread's signal.
4. Methods That Cause State Changes
| Method | From State | To State | Remarks |
|---|---|---|---|
start() | NEW | RUNNABLE | Starts thread execution. |
yield() | RUNNABLE | RUNNABLE | Hints to scheduler to let other threads run. Still RUNNABLE. |
sleep(long millis) | RUNNABLE | TIMED_WAITING | After sleep finishes → RUNNABLE. |
wait() | RUNNABLE | WAITING | Must be inside synchronized block. Needs notify. |
wait(long timeout) | RUNNABLE | TIMED_WAITING | After timeout or notify → RUNNABLE. |
join() | RUNNABLE | WAITING | Waits for another thread to finish. |
join(long millis) | RUNNABLE | TIMED_WAITING | Waits up to given time. |
notify() / notifyAll() | (on another thread) | WAITING/TIMED_WAITING → RUNNABLE | Moves waiting thread(s) to runnable. |
| Attempt to acquire lock (synchronized) | RUNNABLE | BLOCKED | When lock is held by another thread. |
| Lock becomes available | BLOCKED | RUNNABLE | The thread competes for CPU. |
run() completes | RUNNABLE | TERMINATED | Thread ends. |
5. Important Methods That Affect State
a) sleep()
- Causes the current thread to pause for a specified duration.
- Does not release any locks held by the thread.
- After the time elapses, the thread moves back to RUNNABLE.
b) yield()
- A hint to the scheduler that the current thread is willing to give up its current CPU slice.
- The thread stays in RUNNABLE state; it may be immediately rescheduled.
- Not guaranteed; used rarely.
c) join()
- Allows one thread to wait for the completion of another.
- If
t.join()is called from the main thread, the main thread waits untiltfinishes.
d) wait() / notify() / notifyAll()
- Used for inter‑thread communication.
- Must be called from a synchronized context.
wait()releases the lock and enters WAITING/TIMED_WAITING.notify()wakes up one waiting thread (which then tries to re‑acquire the lock).notifyAll()wakes up all waiting threads.
e) interrupt()
- Sets the interrupt flag of the thread.
- If the thread is in WAITING/TIMED_WAITING, it throws
InterruptedExceptionand clears the interrupt flag. - Does not force termination; the thread must handle the interruption.
6. Checking Thread State
You can get the state of a thread using the getState() method. This is useful for debugging.
7. Common Pitfalls and Best Practices
| Pitfall | Explanation / Solution |
|---|---|
Assuming yield() gives up CPU | yield() is just a hint; the thread may continue running. |
Not handling InterruptedException | Methods like sleep(), wait(), join() throw InterruptedException. Always handle it (restore interrupt or exit gracefully). |
Calling wait() without synchronization | Throws IllegalMonitorStateException. Must be inside a synchronized block on the same object. |
Using Thread.stop() (deprecated) | Unsafe; use a flag and check it periodically. |
| Not releasing locks when waiting | wait() releases the lock; sleep() does not. Understand the difference. |
| Deadlocks due to lock ordering | Threads can be BLOCKED forever if locks are acquired in inconsistent order. |
[!TIP] Best Practices:
- Prefer
java.util.concurrentutilities (CountDownLatch,BlockingQueue,Executors) over low‑levelwait/notify. - Use
Thread.join()to wait for termination. - Always name threads for easier debugging.
- Never start a thread in a constructor (it can expose partially constructed object).
- Use
interrupt()to politely ask a thread to stop, and design your thread to respond to interruptions.
8. Complete Example: Observing Thread States
Possible output (order may vary):
9. Key Points to Remember
- A thread goes through NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → TERMINATED.
- RUNNABLE encompasses both ready and running states.
- BLOCKED is for waiting to enter a synchronized block/method.
- WAITING and TIMED_WAITING are for indefinite or time‑limited waiting (e.g.,
wait(),join(),sleep()). sleep()does not release locks;wait()does.yield()is a hint; the thread may not yield.- Use
getState()for monitoring (mostly debugging). - Modern concurrent programming favors higher‑level utilities (
java.util.concurrent) over manual state management.
