java线程状态转换由具体方法调用、锁竞争和系统调度触发:new→runnable由start()唯一触发;runnable↔blocked由synchronized锁竞争引起;runnable↔waiting/timed_waiting由wait()/sleep()等主动让出cpu导致;runnable→terminated发生在run()完成或未捕获异常时。

Java线程状态转换不是由JVM凭空决定的,而是由具体方法调用、锁竞争、系统调度等底层动作直接触发。每种状态变化背后都有明确的执行点和资源行为,理解这些机制才能准确诊断线程卡顿、死锁或响应延迟问题。
NEW → RUNNABLE:start() 启动并绑定操作系统线程
调用 Thread.start() 是唯一合法进入 RUNNABLE 的方式。它不直接执行 run() 方法,而是触发 JVM 执行以下操作:
- 向操作系统发起线程创建请求(如 Linux 下调用
pthread_create) - 为线程分配内核栈、寄存器上下文、线程本地存储(TLS)等 OS 级资源
- 将线程注册进 JVM 线程列表,并标记为“已启动”
- 线程进入操作系统就绪队列,等待 CPU 调度 —— 此时 JVM 即将其状态设为 RUNNABLE
注意:重复调用 start() 会抛出 IllegalThreadStateException;仅 new Thread() 不触发任何 OS 操作,线程始终停留在 NEW。
RUNNABLE ↔ BLOCKED:synchronized 锁获取失败的瞬时挂起
BLOCKED 状态只由 synchronized 关键字引发,与 java.util.concurrent.locks 无关。其底层机制是:
- 当线程尝试进入 synchronized 块/方法时,JVM 检查对应对象监视器(monitor)的 owner 字段
- 若 owner 非空(已被其他线程持有),当前线程立即从 CPU 调度队列移出,加入该 monitor 的 EntryList(阻塞队列)
- 此时线程不再参与 CPU 时间片竞争,JVM 将其状态设为 BLOCKED
- 当 owner 线程退出同步块、释放 monitor 时,JVM 从 EntryList 唤醒一个线程(FIFO 或竞争策略),使其重回 RUNNABLE
该过程不涉及任何 Java 方法调用,完全由 JVM 解释器或 JIT 在字节码 monitorenter 指令处拦截实现。
RUNNABLE ↔ WAITING / TIMED_WAITING:主动让出 CPU 并释放 monitor
WAITING 和 TIMED_WAITING 是线程**主动放弃执行权**的结果,核心特征是:释放 CPU + 释放持有的 monitor 锁(如果正在持有)。
-
WAITING:由
Object.wait()、Thread.join()、LockSupport.park()触发;线程进入对象 monitor 的 WaitSet,必须依赖notify()/notifyAll()或目标线程终止才能恢复 -
TIMED_WAITING:由
Thread.sleep(long)、Object.wait(long)、Thread.join(long)、LockSupport.parkNanos()触发;除加入 WaitSet 或专用等待队列外,还会在 JVM 内部注册定时器事件,超时后自动唤醒并回到 RUNNABLE
注意:sleep() 不释放锁,但仍是 TIMED_WAITING;而 wait() 必须在 synchronized 块内调用,否则抛 IllegalMonitorStateException。
RUNNABLE → TERMINATED:run() 完成或未捕获异常
TERMINATED 是不可逆的终态,仅在以下两个确切时刻发生:
- 线程的 run() 方法正常执行完毕,JVM 清理其栈帧、释放线程私有资源(如虚拟机栈、PC 计数器),并从线程组中注销
- run() 中抛出 **未捕获的异常或错误**(如
NullPointerException、OutOfMemoryError),且未被Thread.UncaughtExceptionHandler拦截处理
一旦进入 TERMINATED,线程对象仍可访问(如调用 getState() 返回 TERMINATED),但不能再调用 start() —— JVM 会拒绝重建 OS 线程资源。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











