notify只能唤醒同一对象等待队列中因wait()阻塞的waiting线程,对blocked、timed_waiting(非wait引起)、park/join等状态及其他对象上的线程无效;须同锁、同对象、在synchronized内调用,并配合while循环防虚假唤醒。

notify 方法只能唤醒处于同一对象监视器(monitor)等待队列中的线程,无法唤醒处于其他锁状态的线程。
notify 只作用于 wait() 的线程
调用 notify() 前,目标线程必须已通过 obj.wait() 进入该对象的等待队列(wait set)。这个过程隐含两个前提:
- 线程必须先获得
obj的 monitor 锁(即在 synchronized(obj) 块中) - 调用
wait()后会自动释放该锁,并挂起,进入obj的等待队列
因此,notify() 只能唤醒那些因 obj.wait() 而阻塞、且正在 obj 等待队列里的线程。它对以下情况无效:
- 正在执行 synchronized 代码但尚未 wait 的线程(它们持有锁,未阻塞)
- 因 I/O、sleep()、park() 等方式阻塞的线程
- 在其他对象(如 obj2)上 wait 的线程
- 处于 BLOCKED 状态(争抢锁失败)的线程
不同锁状态的线程不会被 notify 影响
Java 中线程的常见阻塞状态及其与 notify 的关系如下:
-
WAITING(由 wait() 引起):只有该状态且在目标对象等待队列中,才可能被
notify()唤醒 - BLOCKED(锁竞争中):正等待获取某个对象锁,不响应 notify;需等持有锁线程释放后自然竞争
-
TIMED_WAITING(如 sleep、wait(timeout)):若由
wait(long)进入,可被 notify 提前唤醒;但Thread.sleep()或LockSupport.parkNanos()完全不受 notify 影响 - WAITING(由 join、park 引起):这些是 JVM 级别的等待,与 monitor 无关,notify 无作用
正确使用 notify 的关键点
要让 notify 生效,必须保证“锁对象一致”和“执行时机合理”:
- notify 和 wait 必须在同一个对象上操作,例如都作用于
sharedObj - notify 必须在 synchronized(sharedObj) 块内调用,否则抛出 IllegalMonitorStateException
- 避免虚假唤醒,wait 应始终放在 while 循环中检查条件,而不是 if
- 若存在多个等待线程且条件不完全相同,优先考虑
notifyAll(),避免唤醒错的线程导致条件不满足而继续 wait
替代方案:更灵活的线程通信机制
当需要跨锁、跨条件或更精确控制唤醒时,notify/notifyAll 显得僵硬。推荐使用:
- java.util.concurrent.locks.Condition:配合 ReentrantLock,一个锁可关联多个 Condition,实现分组唤醒
- BlockingQueue(如 ArrayBlockingQueue):生产者-消费者场景下自动处理阻塞与唤醒
- CountDownLatch / Phaser / CyclicBarrier:适用于固定协作模式的线程同步
- LockSupport:底层支持,可精准 unpark 指定线程,但需自行管理状态和安全性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











