wait和notify必须在synchronized块中调用,否则抛IllegalMonitorStateException;需用同一锁对象、while循环检测条件、volatile或锁保护条件变量,优先用notifyAll(),禁用sleep轮询。

wait 和 notify 必须在 synchronized 块中调用
直接调用 wait() 或 notify() 会抛出 IllegalMonitorStateException。JVM 要求当前线程必须持有对象的监视器锁(即已进入该对象的 synchronized 块或方法),否则无法参与等待队列调度。
常见错误是只对共享变量加锁,却在另一个对象上调用 wait();或者用 ReentrantLock 替代 synchronized 后仍误调原生 wait() —— 这两者不兼容。
- 正确做法:所有
wait()、notify()、notifyAll()都写在同一个对象的synchronized块里,且该对象就是调用方 - 推荐共用一个显式锁对象(如
private final Object lock = new Object();),避免混用this引发意外唤醒 - 不要在循环外调用
wait():条件可能被虚假唤醒,必须用while检查条件而非if
生产者要等缓冲区不满,消费者要等缓冲区非空
典型场景是单个共享队列(如 ArrayList 或数组),容量有限。生产者不能无限制塞数据,消费者也不能从空队列取数据——这正是 wait() 的用武之地。
关键不是“谁先执行”,而是每次操作前都检查状态,并在不满足时主动让出锁、进入等待队列。
- 生产者逻辑:进入
synchronized(lock)→while (queue.size() >= capacity) lock.wait();→ 添加元素 →lock.notifyAll(); - 消费者逻辑:同上同步块 →
while (queue.isEmpty()) lock.wait();→ 移除并返回元素 →lock.notifyAll(); - 用
notifyAll()而非notify()更安全:多个生产者/消费者共存时,单个notify()可能唤醒同类线程(比如唤醒另一个生产者),导致死锁
notifyAll() 不等于“立刻唤醒全部”,只是把它们移出等待队列
调用 notifyAll() 后,所有等待线程会竞争重新获取锁。谁先拿到、谁先检查条件、谁先执行后续逻辑,由 JVM 调度决定,不可预测。
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
这意味着即使你刚 notifyAll(),也可能出现:消费者拿到锁后发现队列又空了(因另一个消费者抢先取走最后一个元素),于是再次 wait()。
- 所以条件检查必须是
while循环,不能省略 -
notifyAll()开销比notify()大,但在生产环境更可靠;若确定只有单一生产者+单一消费者,且严格配对,可考虑notify() - 注意:唤醒不保证按等待顺序,没有 FIFO 语义
别忘了中断处理和异常边界
wait() 可能被中断,抛出 InterruptedException。忽略它会导致线程无法响应中断信号,违反协作式中断原则。
另外,wait() 被唤醒后重新获得锁的过程本身也可能被中断(虽然少见),因此需在外层也考虑中断状态。
- 捕获
InterruptedException后应恢复中断状态:Thread.currentThread().interrupt(); - 不要在
catch块里静默吞掉异常,也不要直接抛出(除非上层明确支持) - 如果业务逻辑允许取消等待,可在循环条件中加入
!Thread.currentThread().isInterrupted()
真实系统中,wait/notify 已逐渐被 BlockingQueue(如 ArrayBlockingQueue)替代,后者封装了这些细节。但理解底层机制,对排查锁竞争、虚假唤醒、中断丢失等问题仍很关键。

















