wait()和notify()必须在synchronized同步块中调用,否则抛illegalmonitorstateexception;需用while循环而非if检查条件,推荐notifyall()避免死锁;现代开发更推荐使用condition替代。

在 Java 多线程中,wait() 和 notify() 是实现线程间协作的基础工具,但必须配合 synchronized 使用,否则会抛出 IllegalMonitorStateException。它们本质是对象级别的通信机制,用于让线程等待某个条件成立,或通知其他线程条件已变化。
必须在 synchronized 同步块中调用
wait()、notify() 和 notifyAll() 只能在当前线程持有该对象锁的前提下调用。这是因为这些方法操作的是对象的“等待队列”(monitor 的 wait set),而只有获得锁后才能安全访问和修改这个状态。
- 调用
obj.wait()前,线程必须已通过synchronized(obj)获取了obj的锁;调用后,线程释放锁并进入等待状态 -
obj.notify()同样要求当前线程持有obj的锁;它唤醒等待队列中的一个线程(不保证唤醒顺序) - 推荐始终使用
notifyAll(),避免因唤醒遗漏导致死锁(比如多个生产者/消费者场景)
用 while 循环检查条件,而非 if
被唤醒的线程不一定满足继续执行的条件(可能被虚假唤醒,或条件已被其他线程消费)。因此必须用 while 循环重检条件,而不是 if 判断一次就往下走。
// ✅ 正确:循环检查条件
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait();
}
// 拿到元素后处理
item = queue.poll();
}
// ❌ 错误:可能跳过条件检查,导致异常
synchronized (lock) {
if (queue.isEmpty()) {
lock.wait(); // 唤醒后直接执行后续,未再验证
}
item = queue.poll(); // 可能空指针或 NoSuchElementException
}
典型场景:生产者-消费者模型
以共享缓冲区为例,两个线程通过同一把锁(如缓冲区对象)协调:
- 生产者:加锁 → 检查是否满 → 满则
wait()→ 不满则添加数据 →notifyAll()唤醒消费者 - 消费者:加锁 → 检查是否空 → 空则
wait()→ 不空则取数据 →notifyAll()唤醒生产者 - 注意:
notifyAll()能确保至少一个等待方被唤醒,避免信号丢失
替代方案更推荐 Condition
虽然 wait/notify 可用,但现代 Java 更建议使用 java.util.concurrent.locks.Condition:
- 支持多个等待队列(一个
Lock可创建多个Condition),语义更清晰 - 与
ReentrantLock配合,可中断等待(awaitInterruptibly())、超时等待等 - 避免
wait()必须与synchronized绑定的限制,代码可读性和灵活性更高
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











