【问题标题】:Consumer Producer Problem - Is synchronization always necessary?消费者生产者问题 - 是否总是需要同步?
【发布时间】:2019-10-21 23:25:49
【问题描述】:

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

在生产者消费者问题中,

  • 有一个生产者线程和一个消费者线程。
  • 生产者线程调用方法produce,消费者线程调用方法consume。

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() 包含在同步块中。消费者线程不会调用生产(),所以如果我不使用同步关键字将等待调用包含在生产方法中,那么它的行为应该仍然相同,因为生产()只被生产者线程调用。对吗?

【问题讨论】:

    标签: java multithreading wait synchronized producer-consumer


    【解决方案1】:

    两个线程正在添加/删除的缓冲区是一个链表。 Java 的链表不是线程安全的。

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


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

    【讨论】:

    • 这是否意味着如果生产者线程有锁,消费者线程不能改变列表,因为列表是生产者和消费者正在使用的同一个实例的变量?我已经知道的是,如果一个线程拥有锁,另一个线程无法执行该代码。不知道同步是否也可以确保对共享变量的有限访问。你能详细说明这一点吗?
    • @Sibgha:我认为这不是真的。同步意味着一次只有一个线程可以进入 that 方法。所以,这意味着在produce()中不能有两个线程,或者在consume()中不能有两个线程。这并不意味着生产者/消费者不能访问列表,因为另一个线程在不同的同步方法中。
    • 基于此,代码应该在没有同步的情况下工作,因为生产者正在使用不同的方法来更改列表。例如,consume 方法仅适用于 Consumer 线程。
    • @Sibgha:他们使用不同的方法,但不同的方法正在修改同一个列表。因此需要一些锁定来确保列表按预期使用。在这种情况下,同步被用于执行锁定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多