runnable状态表示线程已就绪或正在运行,涵盖操作系统层面的ready和running两种子状态,jvm将其统一抽象为“可调度、可执行”,不区分是否正占用cpu。
因为 runnable 是 java 对“可调度、可执行”这一抽象层的统称,它把操作系统层面的 就绪(ready) 和 运行(running) 两种状态合并为一个逻辑状态,而 jvm 不暴露线程是否正被 cpu 执行的细节。
RUNNABLE 包含两个实际子状态
Java 的 RUNNABLE 状态不是“正在跑”,而是“能跑”——只要没死、没阻塞、没挂起,就归为此类:
-
Ready(就绪):线程已调用
start(),JVM 已为其分配栈和 PC,只等操作系统调度器分发 CPU 时间片;此时它在就绪队列里排队,不占 CPU; -
Running(运行):线程恰好被调度到某个 CPU 核心上,正在执行
run()方法里的代码;但这个状态转瞬即逝,且由 OS 控制,JVM 不单独标记。
Java 把这两者统一叫 RUNNABLE,是因为从应用开发视角看,它们都处于“随时可以执行、无需外部唤醒”的活跃态,区别对业务逻辑无实质影响。
为什么 JVM 不区分 Ready 和 Running
这种设计是刻意为之的抽象简化:
- 线程在 Ready 和 Running 之间切换极频繁(毫秒甚至微秒级),频繁查询并暴露该状态会带来可观开销;
- Java 希望开发者关注“是否可推进”,而非“此刻是否在跑”——比如调用
Thread.yield()或时间片耗尽后,线程回到 Ready,状态仍是RUNNABLE; - 底层调度权在操作系统手中,JVM 无法精确控制或实时感知某线程是否正占用物理核心。
常见误解场景举例
以下情况中,线程状态都是 RUNNABLE,但它其实根本没在 CPU 上执行:
- 刚调用完
thread.start(),还没被调度(纯就绪); - 正在等待 CPU 时间片轮转(多线程竞争激烈时,可能排队数毫秒);
- 刚被
Thread.sleep(1)唤醒,但尚未获得 CPU(进入就绪队列,状态立即变回RUNNABLE); - 执行完一段计算后让出 CPU(如调用
yield()),仍在就绪队列等待下一次调度。
怎么知道线程到底有没有在跑
Java 层面没有标准 API 能直接告诉你“此刻是否在 CPU 上执行”。但你可以间接观察:
- 用
thread.getState()查到是RUNNABLE,只能说明它“没被阻塞/等待/挂起”,不能证明它正在运行; - 配合系统工具,如
jstack查线程堆栈(若显示在执行某段代码,大概率正在运行); - 用
top -H(Linux)或任务管理器(Windows)看对应线程 ID 的 CPU 占用率是否非零; - 注意:即使
RUNNABLE线程的 CPU 使用率为 0%,也不代表它有问题——可能只是刚启动、刚唤醒、或正巧轮空。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











