terminated 是线程执行实体的彻底销毁,不可逆、不可重启;runnable 是唯一能触发终止流程的状态,因仅此状态具备完整上下文以执行收尾逻辑并确保资源安全释放。

因为 RUNNABLE → TERMINATED 的转变,不是暂停、不是挂起,而是 JVM 向操作系统发出的正式“注销请求”——内核线程控制块(task_struct)被回收,栈空间被释放,程序计数器归零,监控器所有权清空,整个线程在系统层面“消失”。这个过程不可逆、不可重启、不可回滚。
它不是“结束任务”,而是“销毁执行实体”
RUNNABLE 状态下的线程仍绑定着 OS 内核线程资源:有独立的栈、寄存器上下文、task_struct 结构体、调度优先级。一旦 run() 方法正常返回或抛出未捕获异常,JVM 会:
- 调用底层 pthread_exit() 或类似系统调用,通知内核回收该线程资源
- 从调度队列中移除对应 task_struct 节点(从双链表中解链)
- 释放用户态栈与内核栈内存
- 清除该线程持有的所有 monitor 锁(避免死锁残留)
- 将 volatile long state 字段设为 EXITED(Linux)或等效终止标记
TERMINATED 不是“还在那儿等唤醒”,而是“已不复存在”
处于 TERMINATED 的 Thread 对象,只是 Java 堆里一个普通对象,和 Runnable 实例无异:
- 它不再对应任何 OS 线程,无法再获得 CPU 时间片
- 调用 start() 会直接抛 IllegalThreadStateException,不是“失败”,而是“语义非法”
- 反射修改 state 字段无效——JVM 不再监听该对象的状态变更,内核也早已释放其 PCB
- 即使保留引用,也无法通过 interrupt()、join()、wait() 等任何线程方法影响它
为什么不能跳过 RUNNABLE 直接到 TERMINATED?
状态机强制要求必须经过 RUNNABLE,是因为:
- 只有 RUNNABLE 状态才拥有完整执行上下文,才能安全执行 run() 的收尾逻辑(如 finally 块、资源清理)
- 若允许 NEW → TERMINATED,意味着线程从未启动,但 JVM 仍要模拟“注销”动作,违背设计一致性
- 若允许 BLOCKED/WAITING → TERMINATED,会导致锁未释放、等待队列未清理、park 未配对 unpark,引发资源泄漏或死锁
真正的终结信号只有一个:run() 执行流彻底退出
无论线程是在 CPU 上飞速执行、在 synchronized 块里卡住、还是睡了 10 秒后醒来,只要 run() 方法体最后一行代码执行完毕(或中途抛出未捕获 Throwable),JVM 就立即触发终止流程:
- 不会等线程“自然消亡”,而是主动发起资源回收
- 不会因 GC 延迟而暂缓注销——状态变 TERMINATED 和资源释放是原子性关联动作
- 哪怕 run() 中只写了一行 System.out.println("done"),执行完即注销











