Проблема нескольких производителей и потребителей в Java (без BlockingQueue) - PullRequest
2 голосов
/ 02 марта 2011

Я освежаю память о параллелизме Java и пытаюсь решить проблему с популярным производителем.Я реализовал приведенный ниже код, который работает правильно, если есть один производитель и один потребитель.Тем не менее, он не работает правильно, если есть несколько производителей / потребителей.Я не понимаю, почему

public class ProducerConsumer {

    static Monitor monitor;

    public ProducerConsumer(int maxSize)
    {
        monitor = new Monitor(maxSize);
        new Producer().start();
        new Producer().start();
        new Consumer().start();
        new Consumer().start();
    }

    class Producer extends Thread{

        @Override
        public void run() {
            while(true)
            {
                try {
                    monitor.insert();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer extends Thread{

        @Override
        public void run() {
            while(true)
            {
                try {
                    monitor.remove();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

     class Monitor {

          int n;
          int maxSize;

         public Monitor(int maxSize)
         {
             n=0;
             this.maxSize = maxSize;
         }

        synchronized void insert() throws InterruptedException 
        {
            if(n==maxSize)
                wait();
            System.out.println("Producer: "+n++);
            if(n==1)
                notifyAll();
        }

        synchronized void remove() throws InterruptedException 
        {
            if(n==0)
                wait();
            System.out.println("Consumer: "+n--);
            if(n==maxSize-1)
                notifyAll();
        }
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer(100);

    }
}

1 Ответ

8 голосов
/ 02 марта 2011

wait() всегда следует использовать следующим образом:

while(condition not met) 
    wait();

В противном случае некоторые потоки могут проснуться и продолжить работу, если условие все еще не выполнено. Есть две возможные причины этой ситуации:

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

Если вам действительно нужно разбудить только один поток, вы можете использовать notify() вместо notifyAll(). Это устраняет первую проблему, но по-прежнему не может защитить вас от ложных пробуждений, поэтому требуется while.

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