Проблема Consumer Producer - всегда ли необходима синхронизация? - PullRequest
1 голос
/ 22 октября 2019

Мой вопрос чисто концептуальный. И просто для более глубокого понимания связи между потоками.

В проблеме Потребитель-производитель

  • Существует один поток-производитель и один поток-потребитель.
  • Производительпоток вызывает метод yield, а поток Consumer вызывает метод take.

Код примера взят здесь

package ProducerConsumer;
import java.util.LinkedList;
import java.util.Queue;
public class ClassicProducerConsumerExample {
    public static void main(String[] args) throws InterruptedException {
        Buffer buffer = new Buffer(2);
        Thread producerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    buffer.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread consumerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    buffer.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        producerThread.start();
        consumerThread.start();
        producerThread.join();
        consumerThread.join();
    }
    static class Buffer {
        private Queue<Integer> list;
        private int size;
        public Buffer(int size) {
            this.list = new LinkedList<>();
            this.size = size;
        }
        public void produce() throws InterruptedException {
            int value = 0;
            while (true) {
                synchronized (this) {
                    while (list.size() >= size) {
                        // wait for the consumer
                        wait();
                    }
                    list.add(value);
                    System.out.println("Produced " + value);
                    value++;
                    // notify the consumer
                    notify();
                    Thread.sleep(1000);
                }
            }
        }
        public void consume() throws InterruptedException {
            while (true) {
                synchronized (this) {
                    while (list.size() == 0) {
                        // wait for the producer
                        wait();
                    }
                    int value = list.poll();
                    System.out.println("Consume " + value);
                    // notify the producer
                    notify();
                    Thread.sleep(1000);
                }
            }
        }
    }
}

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

Я не понимаю, почему я должен заключать wait () и notify () в синхронизированный блок, когда оба потока вызывают разные методы. Поток-потребитель не собирается вызывать производить (), поэтому, если я не заключу вызов ожидания в методе производства с синхронизированным ключевым словом, он все равно должен вести себя так же, потому что продукт () вызывается только потоком-производителем. Это верно?

1 Ответ

1 голос
/ 22 октября 2019

Буфер, из которого оба потока добавляются / удаляются, является связанным списком. Связанный список Java не является поточно-ориентированным.

Однако вы можете абстрагироваться от этой блокировки в самой структуре данных, используя одновременную версию.


Другое последствие: Хотя в этом примере есть только производитель и только один потребитель, это может быть не всегда так. Наличие более одного производителя и / или потребителя может иметь вариант использования, где требуется синхронизация, даже для поточно-ориентированной структуры данных.

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