单生产者多消费者模型调用notify()时出现死锁/无限等待问题排查
为什么单生产者多消费者用
notify()会导致死锁/无限等待? 嘿,这个问题我之前在调试并发代码时也踩过一模一样的坑,咱们来一步步拆解背后的原因:
核心问题:notify()唤醒的线程是随机的,无法保证唤醒目标
notify()的作用是从当前对象的等待池中随机唤醒一个线程,JVM完全不保证它会唤醒哪一个——这就给多消费者场景埋下了隐患。
举个最典型的死锁场景,假设我们的队列容量是1:
- 生产者生产了一个元素,队列满了,调用
wait()进入等待状态。 - 消费者A获取到锁,消费掉元素,队列变空,调用
notify()后释放锁。 - 这时候JVM随机唤醒了另一个消费者B,而不是生产者。
- 消费者B获取锁后检查队列,发现是空的,于是也调用
wait()进入等待。 - 现在生产者还在等待,所有消费者也都在等待,整个系统彻底卡住,没有线程能继续推进——死锁就发生了。
为什么你会疑惑?因为忽略了线程调度的不确定性
你提到“生产者会继续执行”,但这个前提是生产者必须被唤醒才行。如果每次notify()都碰巧唤醒的是其他消费者,生产者就会一直被晾在等待队列里,永远没机会被唤醒,自然就出现了无限等待的情况。
怎么解决?
- 优先用
notifyAll()替代notify():notifyAll()会唤醒所有等待的线程,虽然看起来效率低一点,但能保证所有等待的线程都有机会检查队列状态。那些不需要被唤醒的线程(比如队列空时的消费者)会在重新获取锁后,再次检查条件并调用wait(),而生产者一定会被唤醒,继续生产流程。 - 用高级并发工具类:比如
java.util.concurrent.BlockingQueue,它已经封装了安全的等待唤醒逻辑,不需要你手动处理wait()/notify(),从根源上避免这类问题。
补充:什么时候notify()是安全的?
只有在严格的一对一生产者-消费者场景下(一个生产者线程,一个消费者线程),notify()才是安全的——因为等待池中只有对方线程,唤醒的一定是目标线程。但只要线程数量超过2,尤其是多消费者或多生产者,notify()的随机性就会导致各种诡异的并发问题。
内容的提问来源于stack exchange,提问作者Nishant_Singh
相关产品推荐
相关产品推荐

