Java中wait与notify机制通过共享锁对象实现线程协作:生产者满时wait释放锁,消费者空时wait,满足条件后notifyAll唤醒并重新竞争锁;必须用while循环检查条件、synchronized保护、正确处理中断。

Java 中 wait 与 notify 机制通过线程间协作,让生产者在缓冲区满时暂停、消费者在缓冲区空时暂停,等条件满足后再继续执行,从而避免忙等、资源浪费和数据错乱。
核心逻辑:用锁对象管理等待与唤醒
wait 和 notify 必须作用于同一个锁对象,且只能在 synchronized 块或方法中调用。这个锁对象(比如缓冲区实例)充当“协调中心”,它的等待队列会记录哪些线程因什么条件被挂起。
- 生产者发现 buffer.size() == capacity → 调用 lock.wait(),释放锁并进入等待
- 消费者消费后 buffer.size() 下降 → 调用 lock.notifyAll(),唤醒所有可能等待的线程
- 被唤醒的线程需重新竞争锁,抢到后才继续执行 —— 这一步天然防止竞态
- 必须用 while 而非 if 判断条件,防止虚假唤醒(spurious wakeup)
关键代码结构:同步 + 循环检查 + 等待唤醒
典型实现中,produce() 和 consume() 都是 synchronized 方法,内部用 while 检查状态,不满足就 wait,满足就操作并 notifyAll。
- produce():while (buffer.size() == capacity) wait(); → add() → notifyAll()
- consume():while (buffer.isEmpty()) wait(); → remove() → notifyAll()
- notifyAll() 比 notify() 更稳妥:避免某些线程长期无法被唤醒(比如多个生产者+多个消费者共用一个锁)
- 所有 wait() 调用都必须包裹在 try-catch 中处理 InterruptedException,否则中断信号会被吞掉
常见陷阱与规避方式
实际写错往往不是语法问题,而是语义和协作逻辑出偏差。
立即学习“Java免费学习笔记(深入)”;
- 多个线程共享同一缓冲区,但用了不同锁对象 → 等待和通知失效,线程永远挂起
- 在非同步上下文中调用 wait/notify → 抛 IllegalMonitorStateException
- 用 if 替代 while 判断条件 → 可能跳过检查直接操作,导致 IndexOutOfBoundsException 或空消费
- 忘记 notify 或 notifyAll → 线程卡死,程序无响应
- 缓冲区用 ArrayList 而非线程安全结构 → 仅适合教学演示;高并发场景应优先选用 ArrayBlockingQueue 等 JDK 原生阻塞队列
为什么不用 sleep 而用 wait
sleep 是线程自己休眠,仍持有锁,其他线程无法进入临界区;wait 则主动释放锁,让对方有机会修改共享状态,这才是协作的基础。
- sleep(100):生产者停 100ms,但锁没放,消费者干等
- wait():生产者一等就放手,消费者立刻能拿锁、消费、再通知它继续
- wait 还支持被精确唤醒,sleep 只能靠时间硬等,效率低且不可控


















