Java线程间通信:生产者消费者POC一轮后双线程永久等待问题求助
核心问题定位
- 递归执行链路断裂:原代码依赖递归调用实现连续生产/消费的逻辑,仅在未达到边界值时走
else分支递归。一旦触发边界条件(box=0 或 box=10)进入wait分支,wait返回后没有后续逻辑重新触发方法调用,synchronized方法直接执行完毕,对应线程随即终止。
按原代码执行流举例:消费者线程将box从5减到0后进入wait状态,等生产者notify唤醒时,会从递归栈顶逐层返回,整个方法链执行结束,线程生命周期终止,没有任何后续消费动作。 - 唤醒逻辑闭环缺失:当生产者生产到box=10的上限时,调用notify唤醒处于wait状态的消费者,但消费者被唤醒后直接终止线程,没有反向调用notify叫醒仍处于wait状态的生产者,最终生产者永久阻塞在wait,整个程序停止。
- 线程等待逻辑不规范:原代码使用
if判断等待条件,没有遵循Java wait机制的使用规范——wait被唤醒后需要重新校验条件,这种写法既可能触发虚假唤醒导致的逻辑错误,也进一步加剧了执行链路的断裂。 - notify()唤醒时机错位:
notify()仅能随机唤醒一个处于wait队列的线程,原代码中消费者在box减到0时调用notify,此时生产者还在阻塞等待对象锁、并未进入wait队列,这次唤醒完全无效,没有起到任何通知作用。
可实现持续循环的优化方案
修正核心思路:
- 用无限循环替代递归逻辑,维持生产/消费动作的持续执行入口,从根源上避免递归链断裂的问题
- 将所有等待判断的
if改为while,wait被唤醒后重新校验边界条件,符合Java线程模型的安全要求 - 将边界位置的
notify()替换为notifyAll(),确保所有等待线程都能被唤醒,避免随机唤醒导致的永久阻塞 - 生产/消费动作执行完成后主动唤醒等待线程,形成双向通知的逻辑闭环,避免出现双方都卡在wait的死锁状态
修正后的完整代码:
public class ProducerConsumerWithThreads { synchronized void withdrawBoxConsumer() { while (true) { // 库存为0时消费者进入等待 while (box == 0) { System.out.println("Please put more boxes"); notifyAll(); try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Consumer thread interrupted, exiting"); return; } } box--; System.out.println("Took one box now boxes left " + box); // 消费完成后主动唤醒所有等待线程 notifyAll(); } } synchronized void putBoxProducer() { while (true) { // 库存达到上限时生产者进入等待 while (box == 10) { System.out.println("Please Consume boxes"); notifyAll(); try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Producer thread interrupted, exiting"); return; } } box++; System.out.println("Put one box now boxes are " + box); // 生产完成后主动唤醒所有等待线程 notifyAll(); } } public int box = 5; public static void main(String[] args) throws InterruptedException { final ProducerConsumerWithThreads c = new ProducerConsumerWithThreads(); new Thread(c::withdrawBoxConsumer, "consumer-thread").start(); new Thread(c::putBoxProducer, "producer-thread").start(); } }
修正后的执行效果:程序会持续在库存为0时触发消费者等待、生产者连续生产,库存到上限时触发生产者等待、消费者连续消费,形成无间断的循环执行逻辑,不会出现两个线程永久阻塞的问题。
内容的提问来源于stack exchange,提问作者Parth
相关产品推荐
相关产品推荐

