消费者生产者问题——同步总是必要的吗?

Consumer Producer Problem - Is synchronization always necessary?

我的问题纯粹是概念性的。并且只是为了更深入地了解线程之间的通信。

在生产者消费者问题中,

The example code is taken from here

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

我读到等待和通知应该在同步块内以避免竞争条件。

我不明白为什么当两个线程调用不同的方法时我应该将 wait() 和 notify() 包含在同步块中。消费者线程不会调用 produce(),所以如果我不使用 synchronized 关键字将 wait 调用包含在 produce 方法中,那么它的行为应该仍然相同,因为 produce() 仅由生产者线程调用。是吗?

两个线程 adding/removing 来自的缓冲区是一个链表。 Java的链表不是线程安全的。

但是,您可以使用 concurrent 版本将这种锁定抽象到数据结构本身。


另一个后果: 虽然在这个例子中只有生产者和一个消费者,但情况可能并非总是如此。拥有多个生产者 and/or 消费者可能会有一个需要同步的用例,即使对于线程安全的数据结构也是如此。