wait/notify 线程间通信
2026/8/24大约 2 分钟
wait/notify 线程间通信
通过 Object 的 wait、notify、notifyAll 实现线程间通信,理解等待池与锁池。
核心方法
Object 是所有类的超类,5 个方法组成等待/通知机制的核心,且均为 final,子类不能覆写:
| 方法 | 说明 |
|---|---|
wait() | 当前线程休眠,直到接到通知或被中断;调用前必须持有该对象锁 |
wait(long) | 带超时时间的等待 |
wait(long, int) | 极少使用,ns 精度难以达到 |
notify() | 随机唤醒一个等待该对象锁的线程 |
notifyAll() | 唤醒所有等待该对象锁的线程 |
使用要点
wait()
- 只能在同步方法或同步块中调用(必须先获得对象级别锁)
- 进入 wait 后释放锁;从 wait 返回前与其他线程竞争重新获得锁
- 未持有锁调用会抛
IllegalMonitorStateException(RuntimeException 子类)
notify()
- 也必须在同步方法/块中调用
- 随机挑选一个 wait 状态的线程发出通知,使其等待获取对象锁
- notify 后当前线程不会马上释放锁,要等退出 synchronized 代码块后,wait 线程才能获取锁
- 如果唤醒的线程运行完毕后再无 notify,其他 wait 线程会继续阻塞——它们等待的是 notify 通知,而不是锁
notifyAll()
- 与 notify 工作方式相同,但唤醒所有在对象上 wait 的线程
- 所有被唤醒线程变成等待获取锁,锁释放后逐个竞争执行
等待池与锁池
- 线程调用对象的
wait()后进入该对象的等待池,等待池中的线程不会竞争锁 - 有线程调用
notifyAll()/notify()后,被唤醒的线程进入该对象的锁池,锁池中的线程会竞争对象锁 - 优先级高的线程竞争到锁的概率大;没竞争到的留在锁池中,只有再次调用
wait()才回到等待池
带超时的注意点
设置了超时时间时,wait() 返回后无法确定是因为收到通知还是超时。一般通过标志位判断:notify 前改变标志位值,wait 返回后读取标志位;为防止 notify 被遗漏,还需另一个标志位循环判断是否调用 wait()。
深入理解
线程间通信关注的是"等待 notify 通知",而不是"等待锁"。锁只是执行 wait/notify 的前提条件。