Java线程生命周期仅有6种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED,定义在Thread.State枚举中;它们非线性流转,由JVM依实际行为动态切换,且getState()不可用于线程控制逻辑。

Java线程的生命周期只有6种状态,全部定义在 Thread.State 枚举中,不是5种也不是7种,别被过时资料误导。
NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED 这六种状态怎么区分
它们不是按时间顺序线性流转的,而是由 JVM 根据线程实际行为动态切换:
-
NEW:线程对象已创建但start()没调用,此时调isAlive()返回false -
RUNNABLE:包含“正在 CPU 执行”和“就绪等待调度”两种情况,不等于正在运行;I/O 阻塞、synchronized 竞争失败都不会进这个状态 -
BLOCKED:只发生在进入synchronized同步块/方法时,因锁被其他线程持有而挂起 -
WAITING:调用Object.wait()、Thread.join()、LockSupport.park()且没设超时 -
TIMED_WAITING:调用带超时的Thread.sleep(1000)、Object.wait(500)、LockSupport.parkNanos()等 -
TERMINATED:线程 run() 方法正常结束或抛出未捕获异常后到达,不可逆
为什么 jstack 输出里看不到 RUNNABLE 却看到 “java.lang.Thread.State: RUNNABLE”
这是最常被误解的一点:RUNNABLE 是 JVM 线程状态,而操作系统层面的“running”或“runnable”是另一套概念。jstack 显示的 RUNNABLE 表示该线程在 JVM 看来“可运行”,但它可能正被 OS 调度器挂起、在执行 native 代码(如 IO)、甚至卡在用户态自旋锁里。
- 真实 CPU 占用高?查
top -H或pidstat -t看 OS 级线程状态 - jstack 中长期显示
RUNNABLE但无实际进展?大概率是 native 阻塞(如 socket read、JNI 调用)或死循环,JVM 无法感知 -
BLOCKED和WAITING在 jstack 中会明确标出锁 ID 或等待对象,比RUNNABLE更容易定位问题
Thread.getState() 返回的状态不能用来做线程控制逻辑
因为状态检查和后续操作之间存在竞态:你刚读到 RUNNABLE,下一行它就进了 WAITING;或者读到 TERMINATED,其实只是刚好完成清理但堆内存还没回收完。
立即学习“Java免费学习笔记(深入)”;
- 不要写
if (t.getState() == Thread.State.TERMINATED) { t.start(); }—— 报IllegalThreadStateException - 不要靠轮询
getState()判断线程是否结束,用t.join()或Future.isDone() -
Thread.stop()、Thread.suspend()已废弃,它们依赖状态强制干预,极易导致锁残留和数据不一致
真正关键的是理解状态背后的资源语义:BLOCKED 关联 monitor 锁,WAITING/TIMED_WAITING 关联条件队列或 park 机制,而 RUNNABLE 是唯一不持有任何显式阻塞条件的状态——但它也最不透明。










