线程生命周期与状态转换
理解线程的状态转换是 Java 并发编程的基础。很多死锁、超时、竞态条件问题,都与线程状态的理解有关。
线程的六种状态
Java 线程有六种状态,定义在 Thread.State 枚举中:
状态详解
NEW 状态
线程创建但未启动:
注意:一个线程只能启动一次。多次调用 start() 会抛出 IllegalThreadStateException。
RUNNABLE 状态
调用 start() 后,线程进入 RUNNABLE 状态。但 RUNNABLE 并不代表线程正在 CPU 上运行:
关键点:RUNNABLE 包括了「就绪(Ready)」和「运行(Running)」两种子状态。在 JVM 层面,线程只能告诉我们它是 RUNNABLE,但无法区分这两种子状态。
BLOCKED 状态
线程等待获取 monitor 锁时,处于 BLOCKED 状态:
BLOCKED vs WAITING
WAITING 状态
线程无限期等待另一个线程执行特定操作:
wait() vs sleep()
TIMED_WAITING 状态
线程有限期等待:
TERMINATED 状态
线程执行完毕:
特点:TERMINATED 是线程的最终状态,无法再转换到其他状态。
状态转换实战
场景一:生产者-消费者
状态转换图
常见问题与排查
jstack 线程状态分析
使用 jstack 查看线程状态:
BLOCKED 线程过多
如果大量线程处于 BLOCKED 状态,说明存在严重的锁竞争:
WAITING 线程过多
如果大量线程处于 WAITING 状态,可能是:
- 等待 I/O 完成
- 等待外部服务响应
- 死锁或活锁
状态转换与性能
状态转换的成本
减少状态转换
本章总结
核心要点:
- 六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
- RUNNABLE 包括就绪和运行:无法在 JVM 层面区分
- BLOCKED 等待锁:synchronized 争抢锁时进入
- WAITING 等待通知:wait()/join()/park() 时进入
- TIMED_WAITING 限时等待:sleep()/wait(n)/join(n) 时进入
- jstack 排查:状态分析是排查并发问题的第一步
理解线程状态是学习同步机制的基础。下一节我们将讲解线程池原理与最佳实践。