java - Java中的生产者/消费者代码期间发生意外异常
问题描述
我正在查看一个带有等待和通知的生产者-消费者示例,即使它有时会产生异常。无法弄清楚问题出在哪里。
com.bhatsac.workshop.producerconsumer.ProdNConsumer.consumer(ProdNConsumer.java:55) 的 java.util.LinkedList.removeFirst(Unknown Source) 的线程“Thread-5”java.util.NoSuchElementException 中的异常 com.bhatsac.workshop .producerconsumer.ProdConsumerInvoker.lambda$5 (ProdConsumerInvoker.java:35) 在 java.lang.Thread.run(Unknown Source)
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
public class ProdNConsumer {
LinkedList<Integer> list = new LinkedList<Integer>();
private int LIMIT = 1;
private volatile boolean shutdown = false;
private AtomicInteger counter=new AtomicInteger(0);
private Object lock=new Object();
public void produce() {
while (true) {
synchronized(lock){
System.out.println("In producer :)"+ list.size());
if(this.list.size()==this.LIMIT){
try {
System.out.println("In waiting state producer");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced by thread= "+ Thread.currentThread().getName());
list.add(counter.getAndIncrement());
System.out.println("Going to sleep for a while");
lock.notifyAll();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void consumer() {
while (true) {
synchronized(lock){
System.out.println("In consumer :)");
if(list.size()==0){
try {
System.out.println("In waiting state consumer");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("consumed by thread="+ Thread.currentThread().getName());
list.removeFirst();
lock.notifyAll();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ProdConsumerInvoker {
public static void main(String[] args) {
ProdNConsumer pc= new ProdNConsumer();
Thread tc1=new Thread(()->{pc.consumer();});
new Thread(()->{pc.produce();}).start();
new Thread(()->{pc.produce();}).start();
Thread tp1=new Thread(()->{pc.produce();});
new Thread(()->{pc.consumer();}).start();
new Thread(()->{pc.consumer();}).start();
tp1.start();
tc1.start();
}
}
解决方案
您的生产者和消费者线程使用相同的锁。当消费者醒来并消费一个元素时,它会调用lock.notifyAll()
,这将唤醒所有等待它的消费者和生产者。另一个消费者醒来时认为列表中有项目,但它从空列表中删除了第一个项目,导致异常。
在消费者中if(list.size()==0)
,使用. 而不是while(list.size()==0)
. 类似的推理也适用于生产者。仅仅因为线程被唤醒并不意味着它正在等待的条件为真。这仅意味着在线程唤醒之前条件为真。它必须再次检查它。
推荐阅读
- java - 错误:无法找到或加载主类 org.springframework.boot.loader.PropertiesLauncher - JAVA -SpringBoot Application
- arrays - 从数组中过滤掉数字
- c++ - CURL - 使用内存中的代理证书
- c# - 对 NAT 后面的 Windows 应用程序的安全请求
- push-notification - 应用关闭后 PWA 应用不接收推送通知
- node.js - 使用 fs 从 Nodejs 中的文件读取后无法处理数据
- javascript - NodeJS:创建将设法根据键值动态生成 for 循环的 api
- python-3.x - Paramiko stdout.readlines() 与 channel.recv()
- python - pytest 不承认基类中的 PASSED 依赖项导致派生类中的 SKIPPED 测试
- .net - 如何将 xml 文件从本地系统移动到 Docker