线程的生命周期和状态转换?

2025年 阅读约 8 分钟 面试指南 · Java面试 · Java并发

深入解析Java线程6种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)、完整状态转换图、每种状态的进入和退出条件、与操作系统线程状态的区别,附完整面试模拟。

一句话总结

Java 线程有 6 种状态(定义在 Thread.State 枚举中):NEW(新建,未 start)、RUNNABLE(可运行,包括就绪和运行中)、BLOCKED(阻塞,等待 synchronized 锁)、WAITING(无限等待,wait/join/park)、TIMED_WAITING(超时等待,sleep/wait(timeout)/join(timeout))、TERMINATED(终止)。注意 Java 的 RUNNABLE 合并了操作系统的 Ready 和 Running 两种状态。

初级理解

6 种状态一览

状态说明进入方式
NEW线程创建但未调用 start()new Thread()
RUNNABLE可运行状态(就绪 + 运行中)start()、被唤醒、获取锁
BLOCKED等待 synchronized 锁synchronized 竞争失败
WAITING无限等待,需要其他线程唤醒wait()、join()、park()
TIMED_WAITING超时等待,到时自动唤醒sleep()、wait(timeout)、join(timeout)
TERMINATED线程执行完毕run() 方法结束

状态演示

public class ThreadStateDemo { public static void main(String[] args) throws Exception { // NEW Thread t = new Thread(() -> { try { Thread.sleep(1000); } catch (Exception e) {} }); System.out.println(t.getState()); // NEW // RUNNABLE t.start(); System.out.println(t.getState()); // RUNNABLE // TIMED_WAITING(sleep 中) Thread.sleep(100); System.out.println(t.getState()); // TIMED_WAITING // TERMINATED t.join(); System.out.println(t.getState()); // TERMINATED } }
一句话总结:NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → TERMINATED。

中级深入

完整状态转换图

┌─────────────────────────────┐ │ │ ▼ │ NEW ──start()──> RUNNABLE ──run()结束──> TERMINATED │ ▲ synchronized│ │获取到锁 竞争失败 │ │ ▼ │ BLOCKED─┘ │ wait()/join() │ notify()/notifyAll() park() │ unpark() ▼ ▲ WAITING─┘ │ sleep(timeout) │ 超时到期 wait(timeout) │ notify()/notifyAll() join(timeout) │ parkNanos() │ ▼ ▲ TIMED_WAITING─┘

BLOCKED vs WAITING 的区别

中断响应
特性BLOCKEDWAITING
触发方式synchronized 竞争锁失败wait()、join()、park()
唤醒方式持有锁的线程释放锁notify()、notifyAll()、unpark()
是否在等待队列EntryList(锁竞争队列)WaitSet(条件等待队列)
不响应中断响应中断(抛 InterruptedException)

WAITING 的进入方式

// 1. Object.wait() — 进入 WAITING synchronized (obj) { obj.wait(); // 释放锁,进入 WAITING } // 唤醒:obj.notify() / obj.notifyAll() // 2. Thread.join() — 进入 WAITING thread.join(); // 等待 thread 执行完毕 // 唤醒:thread 执行完毕 // 3. LockSupport.park() — 进入 WAITING LockSupport.park(); // 阻塞当前线程 // 唤醒:LockSupport.unpark(thread)

TIMED_WAITING 的进入方式

// 1. Thread.sleep() — 不释放锁! Thread.sleep(1000); // TIMED_WAITING,1秒后自动恢复 // 2. Object.wait(timeout) synchronized (obj) { obj.wait(1000); // 释放锁,最多等1秒 } // 3. Thread.join(timeout) thread.join(1000); // 最多等1秒 // 4. LockSupport.parkNanos() / parkUntil() LockSupport.parkNanos(1_000_000_000); // 1秒
中级要点:BLOCKED 是等 synchronized 锁,WAITING 是等 notify/join/unpark。sleep 不释放锁,wait 释放锁。

高级拓展

Java 线程状态 vs 操作系统线程状态

Java 的 RUNNABLE 合并了操作系统的 Ready(就绪,等待 CPU 调度)和 Running(运行中)两种状态。这是因为 JVM 不关心操作系统层面的调度细节。

Java 状态操作系统状态
NEW未创建
RUNNABLEReady + Running
BLOCKEDBlocked(等待锁)
WAITING / TIMED_WAITINGWaiting(等待事件)
TERMINATEDTerminated

线程中断与状态

调用 interrupt() 不会直接改变线程状态,而是设置中断标志。线程在 WAITING/TIMED_WAITING 状态下收到中断会抛 InterruptedException 并清除中断标志,回到 RUNNABLE。

// 中断在 WAITING 状态的线程 Thread t = new Thread(() -> { try { Thread.sleep(10000); // TIMED_WAITING } catch (InterruptedException e) { // 被中断后回到 RUNNABLE System.out.println("被中断了"); } }); t.start(); t.interrupt(); // 线程从 TIMED_WAITING → RUNNABLE
高级加分项:知道 Java RUNNABLE 合并了 OS 的 Ready 和 Running,理解中断如何影响线程状态,能画出完整的状态转换图。

实战场景

场景一:监控线程状态

// 通过 ThreadMXBean 监控所有线程状态 ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); long[] threadIds = mxBean.getAllThreadIds(); for (long id : threadIds) { ThreadInfo info = mxBean.getThreadInfo(id); System.out.println(info.getThreadName() + ": " + info.getThreadState()); }

场景二:线程 dump 分析

线上排查问题时,线程 dump 中每个线程都会显示当前状态和堆栈。大量线程处于 BLOCKED 说明锁竞争激烈,大量 WAITING 可能是线程池空闲或等待通知。

常见坑

原因解决方案
sleep 不释放锁sleep 时持有锁,其他线程无法进入用 wait 代替(需要 synchronized)
wait 必须在 synchronized 中否则抛 IllegalMonitorStateException确保在同步块中调用 wait
notify 后状态不立即变化notify 后线程从 WaitSet 移到 EntryList,仍需竞争锁理解 wait→BLOCKED→RUNNABLE 的转换

面试模拟

Q:Java 线程有哪些状态?

A:6 种状态:NEW(新建)、RUNNABLE(可运行,合并了 OS 的 Ready 和 Running)、BLOCKED(等 synchronized 锁)、WAITING(无限等待,wait/join/park)、TIMED_WAITING(超时等待,sleep/wait(timeout))、TERMINATED(终止)。

Q:BLOCKED 和 WAITING 的区别?

A:BLOCKED 是等待 synchronized 锁,线程在 EntryList 中,锁释放后自动竞争;WAITING 是等待其他线程的通知(notify/join/unpark),线程在 WaitSet 中,需要显式唤醒。BLOCKED 不响应中断,WAITING 响应中断。

Q:sleep 和 wait 对线程状态的影响?

A:sleep 使线程进入 TIMED_WAITING不释放锁,超时自动恢复。wait 使线程进入 WAITING(或 TIMED_WAITING),释放锁,需要 notify 唤醒。两者都会让出 CPU。