线程的生命周期在 Java 中是如何定义的?
- 标签:Java并发、Java
🏛 业务架构师
Java 线程六态:NEW(创建未启动)→ RUNNABLE(就绪/运行,Java 把等 CPU 也算在内)→ BLOCKED(等监视器锁)→ WAITING(无限期等待 notify/join)→ TIMED_WAITING(限期等待 sleep/wait(t))→ TERMINATED(结束)。
业务价值:jstack 里的状态分布是系统的"体检报告"——我巡检时的解读口诀:
- 大量 BLOCKED:锁竞争失控——找到锁的持有者(栈里 locked 拥有的那个对象),通常是临界区太长或粒度太粗,按锁优化阶梯处理;
- 大量 WAITING on condition(等 Condition/队列):线程池队列堆积——消费能力跟不上生产,看是下游变慢还是容量不足;
- 大量 WAITING(park):连接池/资源池等待——DB 连接耗尽(慢查询拖住连接不还),连接池等锁是很多"接口全超时"的根因;
- TIMED_WAITING(sleep)大量出现:业务代码里用 sleep 做轮询——该换成事件驱动或 MQ 通知,轮询是延迟与资源的双重浪费;
- 死锁:jstack 直接报 "Found one Java-level deadlock"——按栈处理。
状态机思维对业务架构的迁移:线程状态、订单状态、审批单状态本质同构——状态集合明确、迁移条件明确、非法迁移拒绝。我用同样的纪律做业务建模:订单状态机不写 if status == X 散落各处,而是集中定义迁移表(UNPAID→PAID→SHIPPED),任何状态判断都走迁移表——并发下的"重复支付""取消后发货"类资损 bug,根因都是状态迁移没有收口。
一句话:线程六态是排障的读图能力,状态机思维是业务正确性的设计能力——一题两用。
🏗 系统架构师
Java 线程生命周期(Thread.State 枚举六态),我按状态机 + 转换条件讲:
- NEW:new Thread() 创建,未 start;
- RUNNABLE:就绪+运行合一(Java 把"等待 CPU"与"执行中"都算 Runnable)——start() 后进入;注意 Java 层的 RUNNABLE 也覆盖了底层阻塞 IO 的情况(如 socket read 在内核态挂起,Java 状态仍是 RUNNABLE——排障时别被骗);
- BLOCKED:竞争 synchronized 监视器锁失败,等进入同步块;
- WAITING:无限期等待,等他人唤醒——
Object.wait()/LockSupport.park()(Lock/条件队列)、Thread.join();被 notify/unpark/中断唤醒后回 RUNNABLE; - TIMED_WAITING:带超时的等待——
sleep(ms)、wait(ms)、parkNanos、带参 join; - TERMINATED:run 结束(正常/异常),终态不可复活。
高频转换链:拿锁失败 NEW→RUNNABLE→BLOCKED;生产者消费者 wait/notify 在 RUNNABLE↔WAITING 间跳;线程池空闲 worker park 在 WAITING,任务来了 unpark 回 RUNNABLE。
工程视角(排障价值):jstack 里按状态统计——大量 BLOCKED 定位锁竞争(看 owns/waiting 的锁);大量 WAITING 在 park 且堆栈是业务调用 → 可能是线程池队列等待下游超时;RUNNABLE 但卡 socketRead0 → 下游 IO 慢(Java 状态骗人,要看堆栈)。状态 + 栈顶的组合才是定位线程问题的完整信息。
💻 全栈开发专家
Java 线程 6 个状态(Thread.State):
text
NEW new 出来还没 start()
RUNNABLE 可运行(就绪+运行 统称,还包括"阻塞在 IO")
BLOCKED 等抢监视器锁(synchronized 入口)
WAITING 无限期等待:wait()/join()/LockSupport.park()
TIMED_WAITING 限时等待:sleep(ms)/wait(ms)/parkNanos
TERMINATED 执行结束与 OS 五态的区别(必答):Java 的 RUNNABLE 合并了"就绪"和"运行"(调度是 OS 的事,JVM 不感知);更反直觉的是——线程阻塞在 socket 读时,Java 状态依然是 RUNNABLE(BIO 的 read 挂起在内核,JVM 不认为它是 WAITING)。所以别用线程状态判断"卡在网络",要看栈帧位置。
jstack 里的实际用法(工程价值):
- 大量 BLOCKED → 锁竞争,
thread -b(Arthas)直接找持锁者; - 大量 WAITING on condition(park)→ 线程池空闲或等条件,看是不是任务不够/队列空转;
- WAITING (on object monitor) → wait() 忘记 notify 或条件设计错误;
- 排查"线程不退出":TERMINATED 之外的旧线程持续存在,连接/资源泄漏。
状态流转代码小例子:
java
t.start(); // NEW → RUNNABLE
synchronized(lock) { lock.wait(); } // RUNNABLE → WAITING(释放锁)
Thread.sleep(1000); // RUNNABLE → TIMED_WAITING(不释放锁)
t.join(); // 调用方 WAITING,等 t TERMINATED能说出"IO 阻塞也显示 RUNNABLE"这个细节,说明真用 jstack 排查过问题。