我如何针对生产者消费者问题优化以下代码

how can i optimise following code for producer consumer problem

我有 1 个生产者和 2 个(多个)消费者。

以下代码工作正常(没有竞争条件 IMO)但问题是每当缓冲区为空时,每个消费者都在执行无限循环,这只是等待资源。

我该如何优化它?我正在考虑使用类似通知消费者的方法,以防任何东西被添加到缓冲区但在实施中遇到问题。

public class Test {

  public static void main(String[] args) {
    Assembly assembly = new Assembly(new ArrayList<>(), new ReentrantLock(true));

    new Thread(new Runnable() {
      @Override
      public void run() {
        assembly.consume();
      }
    }).start();

    new Thread(new Runnable() {
      @Override
      public void run() {
        assembly.produce();
      }
    }).start();

    new Thread(new Runnable() {
      @Override
      public void run() {
        assembly.consume();
      }
    }).start();
  }
}

class Assembly {

  List<Integer> buffer;
  Lock bufferLock;

  public Assembly(List<Integer> buffer, Lock bufferLock) {
    this.buffer = buffer;
    this.bufferLock = bufferLock;
  }

  public void produce() {
    Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 99};
    Random random = new Random();
    for (Integer num : nums) {
      try {
        bufferLock.lock();
        buffer.add(num);
        if (num != 99) {
          System.out.println("Added: " + num);
        }
      } finally {
        bufferLock.unlock();
        try {
          Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException e) {
        }
      }
    }
  }

  public void consume() {
    while (true) {
      try {
        bufferLock.lock();
        if (buffer.isEmpty()) {
          **IS SOME OPTIMISATION POSSIBLE HERE?**
          continue;
        }
        if (buffer.get(0).equals(99)) {
          break;
        }
        System.out.println(
            "Removed: " + buffer.remove(0) + " by " + Thread.currentThread().getName());
      } finally {
        bufferLock.unlock();
      }
    }
  }
}

使用 semaphore 而不是尝试自己动手。消费者将等到 'item' 可用,并且只有一个人会醒来拿到商品。

经典的 producer-consumer solution 使用两个信号量,'other' 一个被生产者用来等待 'free slot' 可用。否则,生产者可能会超越消费者跟上的能力。你的程序看起来对生产有一个小的有限限制,所以这可能不适用于这里。

使用 Semaphore 到 add/remove 个可用元素

public class ProducerConsumer {
    List<Integer> buffer = new ArrayList<>();
    Semaphore available = new Semaphore(0);

    public static void main(String... args) {
        ProducerConsumer pc = new ProducerConsumer();
        new Thread(pc::consume).start();
        new Thread(pc::produce).start();
        new Thread(pc::consume).start();
    }

    public void produce() {
        Integer[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 99};
        Random random = new Random();
        for (Integer num : nums) {
            try {
                synchronized (buffer) {
                    buffer.add(num);
                }
                available.release();
                System.out.println("Added: " + num);
            } finally {
                try {
                    Thread.sleep(random.nextInt(1000));
                } catch (InterruptedException e) {
                }
            }
        }
    }

    public void consume() {
        while (true) {
            try {
                available.acquire();
                synchronized (buffer) {
                    if (buffer.get(0).equals(99)) {
                        break;
                    }
                    System.out.println(
                            "Removed: " + buffer.remove(0) + " by " + Thread.currentThread().getName());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

您的(消费者)线程将被阻塞,直到有新项目可用。

有输出

Added: 1
Removed: 1 by Thread-0
Added: 2
Removed: 2 by Thread-2
Added: 3
Removed: 3 by Thread-0
...