Неожиданное исключение происходит во время кода производителя / потребителя в Java - PullRequest
0 голосов
/ 21 января 2020

Я смотрел на пример производителя-потребителя с ожиданием и уведомлением, хотя он иногда работает и дает исключение. Не удалось выяснить, в чем проблема.

Исключение в потоке "Thread-5" java .util.NoSuchElementException at java .util.LinkedList.removeFirst (Неизвестный источник) в com .bhatsa c .workshop.producerconsumer.ProdNConsumer.consumer (ProdNConsumer. java: 55) по адресу com.bhatsa c .workshop.producerconsumer.ProdConsumerInvoker.lambda $ 5 (101 * по адресу: 101 * 352 по адресу: 101 * 352 по адресу: 132: 352) по адресу:. * .lang.Thread.run (неизвестный источник)

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();

}
 }

1 Ответ

2 голосов
/ 21 января 2020

Потоки вашего производителя и потребителя используют одну и ту же блокировку. Когда потребитель просыпается и потребляет элемент, он вызывает lock.notifyAll(), что разбудит всех потребителей и производителей, ожидающих его. Другой потребитель просыпается, думая, что в списке есть элементы, но он удаляет первый элемент из пустого списка, вызывая исключение.

В потребителе вместо if(list.size()==0) используйте while(list.size()==0). Аналогичные рассуждения применимы и к производителю. То, что поток проснулся, не означает, что условие, в котором он находится, является верным. Это только означает, что до того, как нить проснулась, условие было истинным. Он должен проверить это снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...