Java线程生命周期由Thread.State定义为六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED;NEW经start()进入RUNNABLE,后者涵盖READY和RUNNING子态;BLOCKED由锁竞争引起,WAITING/TIMED_WAITING由协作等待触发;TERMINATED为不可逆终点,仅由run()返回或未捕获异常导致。

Java 线程生命周期由 Thread.State 枚举明确定义为六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。这些状态不是线性流程,而是围绕资源竞争、调度机制与显式控制形成的动态网络。理解每种状态的触发条件和退出路径,是排查死锁、线程饥饿、响应迟滞等并发问题的关键。
NEW → RUNNABLE:启动即不可逆
线程对象被 new Thread(...) 创建后,仅是一个普通 Java 对象,尚未与操作系统线程关联,处于 NEW 状态。此时调用 start() 是唯一合法进入 RUNNABLE 的方式。
- 重复调用
start()会抛出IllegalThreadStateException - 直接调用
run()不会改变线程状态,只是在当前线程同步执行,不开启新线程 - 一旦
start()返回,线程立即进入 RUNNABLE,但不保证立刻执行 —— 它可能在就绪队列中等待调度
RUNNABLE 是“可运行”,不是“正在运行”
RUNNABLE 涵盖两个底层事实:线程已由 JVM 绑定 OS 线程、具备执行资格;但它既包括 CPU 上实际执行的 RUNNING 子态,也包括排队等待 CPU 的 READY 子态。JVM 不暴露子态区分,统一视为 RUNNABLE。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 常见误解:看到
getState() == RUNNABLE就认为线程卡住了?不一定——它可能正高效运行,也可能刚被时间片抢占而排队中 - I/O 阻塞(如传统 BIO 读文件)会使线程脱离 RUNNABLE,进入操作系统级阻塞,Java 层面表现为 TIMED_WAITING 或 BLOCKED(取决于是否涉及锁)
- 使用
Thread.onSpinWait()或忙等待循环时,线程仍属 RUNNABLE,但持续消耗 CPU
BLOCKED vs WAITING/TIMED_WAITING:锁 vs 协作
三者都暂停执行,但原因与唤醒机制截然不同:
立即学习“Java免费学习笔记(深入)”;
-
BLOCKED:争抢
synchronized锁失败所致。线程持有锁时不会进入此态;只有尝试进入已被占用的同步块/方法时,才会挂起并等待锁释放。锁一空出,JVM 自动将其转回 RUNNABLE -
WAITING:主动放弃 CPU 并释放锁(若在 synchronized 块内),等待其他线程显式唤醒。典型入口:
Object.wait()、Thread.join()(无参)、LockSupport.park() -
TIMED_WAITING:带超时的协作等待,超时自动恢复。典型入口:
Thread.sleep()、Object.wait(1000)、Thread.join(500)、LockSupport.parkNanos()
TERMINATED:终点不可逆,资源已回收
线程进入 TERMINATED 只有两种可靠路径:run() 方法自然返回,或 run() 中抛出未捕获异常(含 Error)。此时 JVM 已清理其栈帧、释放本地线程资源,仅保留 Thread 对象实例。
- 不能对 TERMINATED 线程再次调用
start(),否则抛出异常 -
interrupt()对 TERMINATED 线程无效;其isInterrupted()返回false,且中断状态不可重置 - 监控工具(如 JConsole、jstack)中看到 TERMINATED 线程,通常说明该线程对象未被及时 GC,属于内存泄漏线索之一

















