首页 > 解决方案 > 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();

}
 }

标签: javaconcurrency

解决方案


您的生产者和消费者线程使用相同的锁。当消费者醒来并消费一个元素时,它会调用lock.notifyAll(),这将唤醒所有等待它的消费者和生产者。另一个消费者醒来时认为列表中有项目,但它从空列表中删除了第一个项目,导致异常。

在消费者中if(list.size()==0),使用. 而不是while(list.size()==0). 类似的推理也适用于生产者。仅仅因为线程被唤醒并不意味着它正在等待的条件为真。这仅意味着在线程唤醒之前条件为真。它必须再次检查它。


推荐阅读