wait()和notify()必须在synchronized块中调用,因wait会释放锁并进入waiting状态,notify唤醒等待线程;condition须用while而非if以防虚假唤醒和条件失效;多数场景应优先使用notifyall()确保语义安全。

Java 中 Object 类的 wait() 和 notify()(以及 notifyAll())是实现线程间协作的基础机制,但它们**必须配合 synchronized 锁使用**,不能单独调用。核心逻辑是:线程在共享对象上“等待条件成立”,另一个线程修改状态后“通知等待者”。
wait() 和 notify() 必须在 synchronized 块中调用
这是因为:wait() 会释放当前线程持有的该对象的 monitor 锁,并进入 WAITING 状态;notify() 则唤醒一个正在该对象上等待的线程。如果没锁就调用,JVM 会抛出 IllegalMonitorStateException。
正确写法示例:
synchronized (sharedObj) {
while (!conditionMet) { // ⚠️ 必须用 while,不是 if
sharedObj.wait(); // 释放锁,挂起当前线程
}
// 条件满足,继续执行
}
为什么 condition 要用 while 循环判断,而不是 if?
因为存在两种常见干扰:
- 虚假唤醒(spurious wakeup):JVM 可能在没有被 notify 的情况下唤醒线程(虽然罕见,但规范允许);
- 多线程竞争下的条件失效:比如多个线程 wait,notify 唤醒一个,但它处理前另一个线程抢先修改了状态并消费了资源。
用 while 可确保每次唤醒后都重新检查条件是否真正成立,不成立则继续 wait。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
notify() vs notifyAll():选哪个?
notify() 随机唤醒一个等待线程;notifyAll() 唤醒所有等待线程(它们会竞争锁,只有一个能进入 synchronized 块)。
推荐优先使用 notifyAll(),除非你明确知道:
- 所有等待线程“等的是同一类条件”且“唤醒任意一个都合理”(如线程池中空闲 worker 等待任务);
- 且不存在“条件覆盖”或“状态歧义”风险(例如生产者-消费者中,若只 notify 一个,但实际有多个消费者在等,可能漏唤醒)。
多数场景(如经典的生产者-消费者、阻塞队列)应使用 notifyAll() 保证语义安全。
典型协作模式:生产者-消费者(基于 Object 监视器)
以一个共享缓冲区为例:
class SharedBuffer {
private String data;
private boolean isEmpty = true;
public void put(String item) throws InterruptedException {
synchronized (this) {
while (!isEmpty) { // 缓冲区满,等待消费
this.wait();
}
data = item;
isEmpty = false;
this.notifyAll(); // 唤醒可能在等消费的消费者
}
}
public String take() throws InterruptedException {
synchronized (this) {
while (isEmpty) { // 缓冲区空,等待生产
this.wait();
}
String item = data;
isEmpty = true;
this.notifyAll(); // 唤醒可能在等生产的生产者
return item;
}
}
}
注意:两个方法都同步在 this 上,共用同一把锁和等待队列,才能正确通信。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










