Java双类同步问题:生产者notify后消费者仍等待求助
问题根源:锁对象不统一!
嘿,这问题太典型了——你写的Producer和Consumer各自用自己的实例对象当锁,导致notify()根本喊不醒对方!
为啥会这样?
你仔细看代码就懂了:
- Producer里的
synchronized(this),锁的是Producer p这个实例 - Consumer里的
synchronized(this),锁的是Consumer c这个实例
notify()方法的作用是唤醒在当前锁对象上等待的线程。所以Producer调用notify(),只能叫醒在Producer对象上wait的线程(也就是它自己),Consumer在自己的锁上睡得死死的,根本听不到这个通知,可不就一直卡在while(buffer.isEmpty()) wait();这里嘛!
怎么解决?
用同一个共享对象作为两个线程的锁就行——这里最适合的就是你们共用的Buffer实例,毕竟两个线程的操作都是围绕它来的。
修改后的代码示例:
Producer类修改:
public class Producer extends Thread { private Buffer buffer; private int total; public Producer(Buffer buffer, int total) { this.buffer = buffer; this.total = total; } public void run() { int count = 0; while(count < total) { synchronized(buffer) { // 改用buffer作为锁对象 try { while(buffer.isFull()) { buffer.wait(); // 在buffer锁上等待 } int val = (int)(Math.random()*100); buffer.insert(val); System.out.println("Producer添加元素:" + val + ",当前buffer大小:" + buffer.getSize()); buffer.notify(); // 唤醒在buffer锁上等待的线程 count++; } catch(InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } } // 可选:模拟生产延迟 try { Thread.sleep(100); } catch(InterruptedException e) {} } } }
Consumer类修改:
public class Consumer extends Thread { private Buffer buffer; private int total; public Consumer(Buffer buffer, int total) { this.buffer = buffer; this.total = total; } public void run() { int count = 0; while(count < total) { synchronized(buffer) { // 同样用buffer作为锁对象 try { while(buffer.isEmpty()) { buffer.wait(); // 在buffer锁上等待 } int val = buffer.remove(); System.out.println("Consumer移除元素:" + val + ",当前buffer大小:" + buffer.getSize()); buffer.notify(); // 唤醒在buffer锁上等待的线程 count++; } catch(InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } } // 可选:模拟消费延迟 try { Thread.sleep(200); } catch(InterruptedException e) {} } } }
额外提醒
- 你用
while循环判断buffer的空/满状态是完全正确的!别改成if,因为线程被唤醒后可能会遇到虚假唤醒(比如多个线程等待时,notify唤醒了一个,但此时buffer状态又不符合条件了),while循环会再次检查条件,确保逻辑安全。 - 处理
InterruptedException时,最好调用Thread.currentThread().interrupt()恢复中断状态,避免后续逻辑忽略中断信号。
这样修改后,Producer和Consumer共用同一个锁对象,notify就能准确唤醒对方,线程间的协作就正常啦!
内容的提问来源于stack exchange,提问作者N. Colostate
相关产品推荐
相关产品推荐

