Java中Object类的wait()和notify()是基于监视器的等待/唤醒机制,必须在synchronized块中调用,且需用while循环检查条件以防虚假唤醒;典型应用如生产者-消费者模型,但工程中推荐使用BlockingQueue等并发工具类。

Java 中 Object 类的 wait() 和 notify() 方法是实现线程间协作的基础工具,但必须在同步上下文中使用,否则会抛出 IllegalMonitorStateException。它们不是“通信协议”,而是“等待/唤醒”机制,核心在于共享对象的监视器(monitor)和条件判断。
wait() 和 notify() 的基本规则
wait() 让当前线程释放锁并进入等待队列;notify() 唤醒一个在该对象上等待的线程(不保证唤醒哪一个);notifyAll() 唤醒所有等待线程。三者都必须在 synchronized 块或方法中调用,且锁对象必须是调用它们的对象本身。
- 调用
obj.wait()前,线程必须已获得obj的锁(即在synchronized(obj) { ... }内) -
wait()会自动释放锁,并让线程挂起;被唤醒后需重新竞争锁,获得锁后才从wait()返回 -
notify()不释放当前锁,也不立即切换线程,只是发信号;被唤醒线程仍需等待当前同步块结束、释放锁后才能继续 - 永远用
while而非if检查等待条件(防止虚假唤醒)
典型场景:生产者-消费者模型
以共享缓冲区为例,两个线程通过同一对象(如 buffer)协调执行:
class Buffer {
private String data;
private boolean hasData = false;
public void put(String value) throws InterruptedException {
synchronized (this) {
while (hasData) { // 条件不满足就等待
this.wait();
}
data = value;
hasData = true;
this.notify(); // 唤醒可能等待获取数据的消费者
}
}
public String take() throws InterruptedException {
synchronized (this) {
while (!hasData) {
this.wait();
}
String result = data;
hasData = false;
this.notify(); // 唤醒可能等待放入数据的生产者
return result;
}
}
}
注意:notify() 在这里用 notifyAll() 更稳妥——尤其当有多个生产者或消费者时,单个 notify() 可能唤醒错误类型的线程,导致死锁。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
常见陷阱与注意事项
这些细节容易出错,直接影响程序正确性:
-
不能在普通方法里直接调用 wait/notify:必须包裹在
synchronized块中,且锁对象一致 -
wait 后要重新检查条件:即使被唤醒,条件也可能仍未满足(比如被其他线程抢先修改),所以必须用
while循环 -
避免 notify 丢失:如果先
notify后wait,且中间没有锁保护,信号会丢失。因此“检查条件 → 等待”必须原子化(靠 synchronized 保证) -
不要对常量或字符串字面量调用 wait/notify:如
"lock".wait(),因为字符串常量池可能导致多个无关类意外共享锁,引发不可预知行为
替代方案建议
虽然 Object.wait()/notify() 是基础,但在实际开发中更推荐使用 java.util.concurrent 包中的高级工具:
-
BlockingQueue(如ArrayBlockingQueue)直接封装了线程安全的生产和消费逻辑 -
Condition配合ReentrantLock提供更灵活的等待队列(可定义多个条件变量) -
CountDownLatch、CyclicBarrier、Semaphore解决特定协同场景,语义更清晰、不易出错
原始 wait/notify 适合学习底层原理或极简控制场景,工程代码中优先选并发工具类。

















