notify()随机唤醒一个在该对象上wait()的线程,需在synchronized块内调用,且wait与notify必须作用于同一对象;适用于一对一协作等明确单线程响应的场景。

在 Java 多线程中,notify() 的作用就是随机唤醒一个正在该对象监视器(即 synchronized 锁对象)上 wait() 的线程——它本身没有“指定唤醒”或“按顺序唤醒”的能力,所谓“随机”是 JVM 实现决定的,开发者无需、也无法控制具体唤醒哪一个。
notify 的基本使用前提
必须满足以下条件,notify() 才能正常工作:
- 调用
notify()的线程必须持有该对象的锁(即必须在synchronized(obj) { ... }块内) - 被唤醒的线程必须此前已在同一对象上调用了
wait()并进入等待队列 -
wait()和notify()必须作用于同一个对象实例
典型协作模式:生产者-消费者示例
下面是一个使用 notify() 随机唤醒单个等待线程的安全示例(注意:实际中更推荐用 notifyAll() 防止信号丢失,但这里聚焦 notify() 行为):
<font size="2"><pre class="brush:php;toolbar:false;">class SharedBuffer {
private String data = null;
public synchronized void produce(String item) throws InterruptedException {
while (data != null) {
wait(); // 等待缓冲区为空
}
data = item;
System.out.println("Produced: " + item);
notify(); // 随机唤醒一个等待的消费者线程
}
public synchronized String consume() throws InterruptedException {
while (data == null) {
wait(); // 等待缓冲区非空
}
String item = data;
data = null;
System.out.println("Consumed: " + item);
notify(); // 随机唤醒一个等待的生产者线程
return item;
}
}
说明:
立即学习“Java免费学习笔记(深入)”;
- 多个消费者线程调用
consume()时,可能都在同一对象上wait();notify()每次只唤醒其中一个(JVM 选择,不可预测) - 必须用
while而非if检查条件,防止虚假唤醒(spurious wakeup)或唤醒后条件已变 - 唤醒后被选中的线程不会立即执行,需重新竞争锁;获得锁后才从
wait()返回,继续执行后续逻辑
notify vs notifyAll:何时选 notify?
notify() 适用于明确“只有一个等待者需要响应”的场景,且能确保唤醒后条件一定成立。常见适用情况包括:
- 一对一协作(如一个生产者 + 一个消费者)
- 等待线程具有相同语义(例如所有等待者都在等“资源可用”,且资源只够服务一个)
- 你完全掌控所有等待线程的行为,并确认唤醒任意一个都安全
⚠️ 注意:在一对多、多对一或多对多场景下,盲目用 notify() 容易导致部分线程永久等待(因为被唤醒的线程发现条件不满足又回去 wait(),而其他线程一直没被唤醒)。此时应优先用 notifyAll()。
调试与验证 notify 是否生效
无法直接“看到”哪个线程被唤醒,但可通过日志间接观察:
- 在每个
wait()前打印线程名(Thread.currentThread().getName()) - 在
notify()后打印“notified”及当前线程名 - 在
wait()返回后立刻打印“awakened”和线程名
运行多线程测试时,你会看到每次只有**一个**等待线程的日志出现 “awakened”,其余仍卡在 “waiting” 状态——这就是 notify() 随机唤醒单个线程的体现。


















