901 字
约 3 分钟
3
S05-B02 · 线程状态机与创建方式

适用读者:分不清 BLOCKED 与 WAITING 的人。
前置:S05-B01。
口径:本系列唯一无旧卡的一篇(原卡 A-1610 归入 S04),内容为 E 驱动;jstack 观察为实测。
覆盖旧文:—(E 驱动)
覆盖扩展:E-S05-003(六状态与 BLOCKED 区别)。
上一篇:S05-B01 · 并发三大特性与 JMM
下一篇:S05-B03 · synchronized 与锁升级。


1. 一句话结论

Java 线程有 6 种状态,判断"卡在哪"只需看两件事:占用 CPU 吗?在等锁还是在等条件?

状态 在等什么 占 CPU
NEW 还没 start() —
RUNNABLE CPU 时间片(含 IO 等待) 可能
BLOCKED 等 monitor 锁 ❌
WAITING 等 notify/join(无超时) ❌
TIMED_WAITING 等超时(sleep/wait(n)) ❌
TERMINATED 已结束 —

关键区别:BLOCKED 专指"等 synchronized 锁";WAITING 是"等别人显式唤醒"。这是面试高频点,也是排障时区分"锁竞争"与"逻辑等待"的依据。


2. start() 与 run():本质不同

调用 行为
t.start() 创建新线程,新线程执行 run()
t.run() 当前线程直接调用方法(没有并发)

判据:"我是在开新线程,还是在调一个普通方法?" 直接调 run 是最常见的"假多线程"bug。


3. 三种创建方式与取舍

方式 写法 取舍
继承 Thread class T extends Thread 占用了继承名额,不推荐
实现 Runnable new Thread(r) 推荐(可再实现其他接口)
Callable + Future 有返回值、可抛异常 需要结果时用
线程池 ExecutorService.submit 生产环境唯一推荐

为什么生产环境不用 new Thread:线程创建/销毁成本高、无上限、无法统一监控——这些正是 B05 线程池要解决的。


4. 用 jstack 看状态(实测方法)

$ jstack <pid> | grep -A 3 "java.lang.Thread.State"

典型输出含义:

输出 解读
RUNNABLE + 栈在 socketRead 实际在等 IO(Java 里网络 IO 也显示 RUNNABLE)
BLOCKED (on object monitor) 等锁 → 查是谁长期持有锁
WAITING (parking) 等 LockSupport.park(AQS 常见)
TIMED_WAITING (sleeping) 在 sleep

注意:RUNNABLE 不等于"在跑"——Java 把"等 IO"也算 RUNNABLE,所以看 CPU 占用要配合 top -H。


5. 五个误区

误区 真相
"run() 会开新线程" 在当前线程执行
"WAITING 和 BLOCKED 一样" 前者等唤醒,后者等锁
"RUNNABLE 就是在用 CPU" 等 IO 也是 RUNNABLE
"sleep(0) 没意义" 会让出 CPU(让同优先级线程有机会)
"线程越多并发越高" 受核数与切换成本限制(S02-B02 实测)

6. 自检

  1. 六种状态分别"在等什么"?哪两个都不占 CPU 却含义不同?
  2. start() 与 run() 的本质差异?
  3. 为什么生产环境不直接 new Thread?
  4. jstack 里 RUNNABLE 但 CPU 不高,可能是什么情况?
  5. WAITING 与 TIMED_WAITING 的区别?

7. 下一篇

S05-B03 · synchronized 与锁升级

状态机讲完,下一篇深入"锁":锁的是什么、三级升级的触发条件,以及为什么偏转锁在 JDK 15+ 被废弃。


本篇属于系列《S05 · Java 并发与 JVM》。本篇为 E 驱动(原卡 A-1610 归 S04);扩展点 E-S05-003。

S05-B02 · 线程状态机与创建方式
https://www.clxhxhhr.top/posts/5243/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。