runnable状态不表示线程正在cpu上执行,而是指线程已就绪、在操作系统就绪队列中等待调度或正被cpu执行,jvm将os的ready和running统一抽象为该状态。

Java 中的 RUNNABLE 状态,常被误解为“正在 CPU 上执行”。实际上,它只是表示线程已准备好运行——可能正真在跑,也可能正排队等 CPU,甚至刚被调度器选中但还没轮到它上核。这个状态是 JVM 对操作系统线程状态的抽象,不直接对应物理 CPU 的占用。
RUNNABLE 包含就绪与运行两个微观状态
JVM 将操作系统的 就绪(ready) 和 运行中(running) 统一归为 RUNNABLE。也就是说:
- 调用
start()后,线程进入 RUNNABLE,此时它可能还在操作系统就绪队列里等待调度; - 只有被 OS 调度器选中、分配了 CPU 时间片,才真正开始执行字节码;
- 时间片用完、或被更高优先级线程抢占,它会回到就绪队列,但仍处于 RUNNABLE 状态。
时间片轮转决定“RUNNABLE → 实际执行”的时机
CPU 并不持续服务某个线程。它按时间片(通常几毫秒)轮转调度所有就绪线程:
- 同优先级线程之间严格轮转:A 执行完时间片 → 让出 CPU → 进入就绪队列尾部 → B 开始执行;
- 线程若主动让出(如
Thread.sleep()、Object.wait()、I/O 阻塞),会立刻退出 CPU,不等时间片耗尽; - 这意味着一个 RUNNABLE 线程可能长时间“卡”在就绪队列中,尤其在高并发、CPU 密集场景下。
阻塞/等待状态才会真正脱离 CPU 竞争
只有进入以下状态,线程才不再参与 CPU 时间片争夺:
- BLOCKED:等待获取 synchronized 锁,不占 CPU;
-
WAITING / TIMED_WAITING:调用
wait()、join()、sleep()等,释放 CPU 并挂起; - NEW / TERMINATED:未启动或已结束,自然不参与调度。
而 RUNNABLE 线程始终在“可被调度”的集合内,哪怕它此刻什么也没干——只是在等轮到自己。
诊断时别被 RUNNABLE “骗”了
用 jstack 或 JFR 查看线程堆栈,大量线程显示 RUNNABLE 并不意味 CPU 过载:
- 可能是线程数远超 CPU 核心数,大量线程在就绪队列排队;
- 也可能是某些线程在做轻量计算+频繁让出(如自旋+yield),看似活跃实则低效;
- 需结合 CPU 使用率、GC 日志、锁竞争统计综合判断,不能单看状态。










