上一篇:线程基础 · 下一篇:JMM 与 volatile
六种状态
java.lang.Thread.State 枚举定义了六种状态(不是操作系统线程的全部状态,而是 JVM 对 Java 线程的建模)。

上图:从 NEW 经 start() 进入 RUNNABLE,再因争锁、等待、限时等待进入 BLOCKED / WAITING / TIMED_WAITING,最后 TERMINATED。
| 状态 | 含义 | 常见触发 |
|---|---|---|
| NEW | 已 new Thread,未 start() | 创建线程对象 |
| RUNNABLE | 可运行(含就绪 + 正在 CPU 执行) | start() 之后 |
| BLOCKED | 等待进入 synchronized 同步块/方法 | 锁被其他线程占用 |
| WAITING | 无限期等待,需他人唤醒 | Object.wait()、Thread.join()(无超时) |
| TIMED_WAITING | 限时等待,时间到或唤醒 | Thread.sleep()、wait(timeout)、join(timeout) |
| TERMINATED | run() 正常结束或异常退出 | 线程执行完毕 |
流转要点(对照上图箭头)
- NEW → RUNNABLE:只能走
start()一次;重复start()抛IllegalStateException。 - RUNNABLE → BLOCKED:抢
synchronized锁失败时进入;拿到锁后回到 RUNNABLE。 - RUNNABLE → WAITING:在已持锁时调用
wait(),或调用join()等待另一线程结束。 - RUNNABLE → TIMED_WAITING:
sleep(ms)、带超时的wait/join。 - WAITING / TIMED_WAITING → RUNNABLE:
notify/notifyAll、超时、中断等唤醒。 - RUNNABLE → TERMINATED:
run()跑完;不能再回到 RUNNABLE,也不能回到 NEW。
和 sleep / wait 的关系(易混)
sleep:线程进入 TIMED_WAITING,不释放 synchronized 锁。wait:线程进入 WAITING(或带超时则为 TIMED_WAITING),释放对象监视器。
源文件(可编辑):assets/java-thread-lifecycle-six-states.svg
sleep() vs wait()
| sleep | wait | |
|---|---|---|
| 所属 | Thread 静态方法 | Object 实例方法 |
| 释放锁 | 不释放 | 释放对象监视器 |
| 唤醒 | 时间到 | notify/notifyAll/中断 |
| 使用场景 | 暂停当前线程 | 线程协作、条件等待 |
wait/notify 使用要点
- 必须在 synchronized 同步块 内调用,否则
IllegalMonitorStateException - 定义在 Object 上:锁是对象级,不是线程级
- 用 while 循环 检查条件,防止伪唤醒
notify()唤醒一个;notifyAll()唤醒全部,由锁竞争决定谁继续
synchronized (lock) { while (!condition) { lock.wait(); } // 执行业务 lock.notifyAll();}join() — 顺序执行
Thread t1 = new Thread(() -> task1());Thread t2 = new Thread(() -> task2());t1.start();t1.join(); // 等 t1 结束t2.start();t2.join();T1→T2→T3 顺序可用链式 join。
yield() 与 sleep(0)
yield() 提示调度器让出 CPU,不保证其他线程立刻运行。sleep(0) 可触发重新分配时间片。
守护线程 vs 用户线程
- 用户线程:前台业务线程
- 守护线程:JVM 退出时自动结束(如 GC 辅助),必须伴随用户线程
Thread daemon = new Thread(() -> { /* ... */ });daemon.setDaemon(true);daemon.start();停止线程
不推荐 stop()。推荐:协作式 volatile 标志 + 循环检查,或 interrupt() + 正确处理 InterruptedException。
线程间传数据
- 共享对象 + 同步(wait/notify、
BlockingQueue) BlockingQueue是生产者-消费者常用手段
阻塞式方法
调用方在结果返回前被挂起,如 ServerSocket.accept()、InputStream.read()、Future.get()。
排查:jstack
jstack <pid> > thread.dumpLinux 可用 kill -3 <pid>;配合 jps 查 pid。
一句话总结
状态流转决定排查思路;协作用 wait/notify 必须在同步块 + while;顺序用 join;停止用 interrupt 而非 stop。