线程生命周期与通信

笔记/Java/Java基础/Java并发/线程生命周期与通信

上一篇:线程基础 · 下一篇:JMM 与 volatile

六种状态#

java.lang.Thread.State 枚举定义了六种状态(不是操作系统线程的全部状态,而是 JVM 对 Java 线程的建模)。

图片预览
图片预览

上图:从 NEWstart() 进入 RUNNABLE,再因争锁、等待、限时等待进入 BLOCKED / WAITING / TIMED_WAITING,最后 TERMINATED

状态含义常见触发
NEWnew Thread,未 start()创建线程对象
RUNNABLE可运行(含就绪 + 正在 CPU 执行)start() 之后
BLOCKED等待进入 synchronized 同步块/方法锁被其他线程占用
WAITING无限期等待,需他人唤醒Object.wait()Thread.join()(无超时)
TIMED_WAITING限时等待,时间到或唤醒Thread.sleep()wait(timeout)join(timeout)
TERMINATEDrun() 正常结束或异常退出线程执行完毕

流转要点(对照上图箭头)

  1. NEW → RUNNABLE:只能走 start() 一次;重复 start()IllegalStateException
  2. RUNNABLE → BLOCKED:抢 synchronized 锁失败时进入;拿到锁后回到 RUNNABLE。
  3. RUNNABLE → WAITING:在已持锁时调用 wait(),或调用 join() 等待另一线程结束。
  4. RUNNABLE → TIMED_WAITINGsleep(ms)、带超时的 wait/join
  5. WAITING / TIMED_WAITING → RUNNABLEnotify/notifyAll、超时、中断等唤醒。
  6. RUNNABLE → TERMINATEDrun() 跑完;不能再回到 RUNNABLE,也不能回到 NEW。

sleep / wait 的关系(易混)

  • sleep:线程进入 TIMED_WAITING不释放 synchronized 锁。
  • wait:线程进入 WAITING(或带超时则为 TIMED_WAITING),释放对象监视器。

源文件(可编辑):assets/java-thread-lifecycle-six-states.svg

sleep() vs wait()#

sleepwait
所属Thread 静态方法Object 实例方法
释放锁不释放释放对象监视器
唤醒时间到notify/notifyAll/中断
使用场景暂停当前线程线程协作、条件等待

wait/notify 使用要点#

  1. 必须在 synchronized 同步块 内调用,否则 IllegalMonitorStateException
  2. 定义在 Object 上:锁是对象级,不是线程级
  3. while 循环 检查条件,防止伪唤醒
  4. 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#

Terminal window
jstack <pid> > thread.dump

Linux 可用 kill -3 <pid>;配合 jps 查 pid。

一句话总结#

状态流转决定排查思路;协作用 wait/notify 必须在同步块 + while;顺序用 join;停止用 interrupt 而非 stop。

文章目录

文章目录