Заказ уведомлений и ожидания в Java - PullRequest
0 голосов
/ 21 декабря 2018

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

Stack<Integer> buffer = new Stack<>();
volatile int i = 1;

class Consumer implements Runnable {

    @Override
    public void run() {
        while(true){
            synchronized (buffer) {
                System.out.println("Consumer taking lock : " + Thread.currentThread().getName());
                while(buffer.isEmpty()){
                    try{
                        System.out.println("Consumer releasing lock :" + Thread.currentThread().getName());
                        buffer.wait();
                        System.out.println("Consumer woken up :" + Thread.currentThread().getName());
                    } catch(InterruptedException ie){
                        ie.printStackTrace();
                    }
                }
                System.out.println(buffer.pop());
                buffer.notify();
            }
        }
    }
}

class Producer implements Runnable {

    @Override
    public void run() {
        while(true){
            synchronized (buffer) {
                System.out.println("Producer taking lock : " + Thread.currentThread().getName());
                while(!buffer.isEmpty()){
                    try {
                        System.out.println("Producer going into wait set :" + Thread.currentThread().getName());
                        buffer.wait();
                        System.out.println("Producer woken up :" + Thread.currentThread().getName());
                    } catch (InterruptedException ie) {
                        ie.printStackTrace();
                    }
                }
                buffer.push(i);
                i++;
                buffer.notify();
            }
        }
    }

}

public static void main(String[] args) {

    ProducerConsumerUnitBuffer obj = new ProducerConsumerUnitBuffer();
    Thread producerThread1 = new Thread(obj.new Consumer());
    Thread consumerThread1 = new Thread(obj.new Producer());
    Thread producerThread2 = new Thread(obj.new Consumer());
    Thread consumerThread2 = new Thread(obj.new Producer());
    Thread producerThread3 = new Thread(obj.new Consumer());
    Thread consumerThread3 = new Thread(obj.new Producer());
    Thread producerThread4 = new Thread(obj.new Consumer());
    Thread consumerThread4 = new Thread(obj.new Producer());
    Thread producerThread5 = new Thread(obj.new Consumer());
    Thread consumerThread5 = new Thread(obj.new Producer());
    Thread producerThread6 = new Thread(obj.new Consumer());
    Thread consumerThread6 = new Thread(obj.new Producer());
    Thread producerThread7 = new Thread(obj.new Consumer());
    Thread consumerThread7 = new Thread(obj.new Producer());
    Thread producerThread8 = new Thread(obj.new Consumer());
    Thread consumerThread8 = new Thread(obj.new Producer());
    Thread producerThread9 = new Thread(obj.new Consumer());
    Thread consumerThread9 = new Thread(obj.new Producer());
    Thread producerThread10 = new Thread(obj.new Consumer());
    Thread consumerThread10 = new Thread(obj.new Producer());

    producerThread1.start();
    consumerThread1.start();
    producerThread2.start();
    consumerThread2.start();
    producerThread3.start();
    consumerThread3.start();
    producerThread4.start();
    consumerThread4.start();
    producerThread5.start();
    consumerThread5.start();
    producerThread6.start();
    consumerThread6.start();
    producerThread7.start();
    consumerThread7.start();
    producerThread8.start();
    consumerThread8.start();
    producerThread9.start();
    consumerThread9.start();
    producerThread10.start();
    consumerThread10.start();

}

Этот код всегда останавливается.Хотя приложение не завершает работу, оно прекращает печатать что-либо, что означает, что ни один поток не входит в синхронизированный блок.

Хотя, когда я использую notifyAll () вместо notify () , код работаетотлично.

РЕДАКТИРОВАТЬ

В соответствии с предложениями я попытался изменить код так, чтобы для производителей и потребителей было два отдельных объекта, которые можно заблокировать.Кроме того, производители уведомляют () потребителей, когда объект помещается в буфер.

public class ProducerConsumerDifferentObjects {

Stack<Integer> buffer = new Stack<>();
Boolean producerLockingObject = Boolean.FALSE;
Boolean consumerLockingObject = Boolean.TRUE;
volatile int i = 1;

class Consumer implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (consumerLockingObject) {
                while (buffer.isEmpty()) {
                    try {
                        consumerLockingObject.wait();
                    } catch (InterruptedException ie) {
                        ie.printStackTrace();
                    }
                }
                System.out.println(buffer.pop());
                consumerLockingObject.notify();
            }
        }
    }
}

class Producer implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (producerLockingObject) {
                while (!buffer.isEmpty()) {
                    try {
                        producerLockingObject.wait();
                    } catch (InterruptedException ie) {
                        ie.printStackTrace();
                    }
                }
                buffer.push(i);
                i++;
                producerLockingObject.notify();
                synchronized (consumerLockingObject) {
                    consumerLockingObject.notify();
                }
            }
        }
    }
}

public static void main(String[] args) {

    ProducerConsumerDifferentObjects obj = new ProducerConsumerDifferentObjects();
    Thread producerThread1 = new Thread(obj.new Consumer());
    Thread consumerThread1 = new Thread(obj.new Producer());
    Thread producerThread2 = new Thread(obj.new Consumer());
    Thread consumerThread2 = new Thread(obj.new Producer());
    Thread producerThread3 = new Thread(obj.new Consumer());
    Thread consumerThread3 = new Thread(obj.new Producer());
    Thread producerThread4 = new Thread(obj.new Consumer());
    Thread consumerThread4 = new Thread(obj.new Producer());
    Thread producerThread5 = new Thread(obj.new Consumer());
    Thread consumerThread5 = new Thread(obj.new Producer());
    Thread producerThread6 = new Thread(obj.new Consumer());
    Thread consumerThread6 = new Thread(obj.new Producer());
    Thread producerThread7 = new Thread(obj.new Consumer());
    Thread consumerThread7 = new Thread(obj.new Producer());
    Thread producerThread8 = new Thread(obj.new Consumer());
    Thread consumerThread8 = new Thread(obj.new Producer());
    Thread producerThread9 = new Thread(obj.new Consumer());
    Thread consumerThread9 = new Thread(obj.new Producer());
    Thread producerThread10 = new Thread(obj.new Consumer());
    Thread consumerThread10 = new Thread(obj.new Producer());

    producerThread1.start();
    consumerThread1.start();
    producerThread2.start();
    consumerThread2.start();
    producerThread3.start();
    consumerThread3.start();
    producerThread4.start();
    consumerThread4.start();
    producerThread5.start();
    consumerThread5.start();
    producerThread6.start();
    consumerThread6.start();
    producerThread7.start();
    consumerThread7.start();
    producerThread8.start();
    consumerThread8.start();
    producerThread9.start();
    consumerThread9.start();
    producerThread10.start();
    consumerThread10.start();
}

}

1 Ответ

0 голосов
/ 22 декабря 2018

В сценарии несколько производитель / несколько потребитель (MPMC) вы пытаетесь использовать один объект (buffer) для уведомления оба потребителей и производителей.Вот почему вы в конечном итоге застопорились: вместо уведомления производителя один уведомляет другого потребителя .(Или производители уведомляют другого производителя).

Рассмотрим следующий возможный порядок событий:

  1. Потребитель 1 ожидает в пустом буфере.
  2. Потребитель 2 ожидает впустой буфер.
  3. Производитель производит элемент и уведомляет потребителя 1. Затем производитель ожидает непустой буфер.
  4. Потребитель 1 пробуждается, потребляет единственный элемент вбуфер уведомляет потребителя 2 и ожидает на пустом буфере.
  5. Потребитель 2 просыпается, но сразу ждет, потому что буфер пуст.

Итаквсе потребители и производители находятся в состоянии ожидания.

Наличие большего количества потребителей и / или производителей не помогает: все они могут находиться в состоянии ожидания.


Возможные способы решения проблемы:

  1. Наличие различных объектов для уведомления потребителей и производителей.В Java вы можете создать два объекта Condition из единой блокировки, одно условие для уведомляющих потребителей, а другое - для уведомляющих производителей.

  2. Дополнительно синхронизируйте производителей с самими собойи потребители сами с собой.Таким образом, не более одного производителя и единственного потребителя могут ждать на общем объекте.

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


Может случиться так, что изменение условия ожидания для производителей с «буфер не пуст» на «буфер заполнен» поможет в случае емкости буфера 2 элемента или более.уведомление потребителя-потребителя все еще возможно, но, возможно, будет предотвращено полное зависание.Но это было бы очень сложно.

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