2

请复制下面的程序并尝试在您的 IDE 中运行。这是一个简单的 Produce Consumer 实现 - 当我使用一个 Producer 和一个 Consumer 线程时它运行良好,但在每个使用 2 个时失败。请让我知道这个程序挂起的原因或者它还有什么问题。

import java.util.LinkedList;
import java.util.Queue;

public class PCQueue {

 private volatile Queue<Product> productQueue = new LinkedList<Product>();

 public static void main(String[] args) {
  PCQueue pc = new PCQueue();

  Producer producer = new Producer(pc.productQueue);
  Consumer consumer = new Consumer(pc.productQueue);

  new Thread(producer, "Producer Thread 1").start();
  new Thread(consumer, "Consumer Thread 1").start();

  new Thread(producer, "Producer Thread 2").start();
  new Thread(consumer, "Consumer Thread 2").start();
 }

}

class Producer implements Runnable {

 private Queue<Product> queue = null;

 private static volatile int refSerialNumber = 0;

 public Producer(Queue<Product> queue) {
  this.queue = queue;
 }

 @Override
 public void run() {

  while (true) {
   synchronized (queue) {
    while (queue.peek() != null) {
     try {
      queue.wait();
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    queue.add(new Product(++refSerialNumber));
    System.out.println("Produced by: "
      + Thread.currentThread().getName() + " Serial Number: "
      + refSerialNumber);

    queue.notify();
   }
  }

 }
}

class Consumer implements Runnable {

 private Queue<Product> queue = null;

 public Consumer(Queue<Product> queue) {
  this.queue = queue;
 }

 @Override
 public void run() {
  while (true) {
   synchronized (queue) {
    while (queue.peek() == null) {
     try {
      queue.wait();
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    Product product = queue.remove();
    System.out.println("Consumed by: "
      + Thread.currentThread().getName() + " Serial Number: "
      + product.getSerialNumber());

    queue.notify();

   }
  }

 }

}

class Product {
 private int serialNumber;

 public Product(int serialNumber) {
  this.serialNumber = serialNumber;
 }

 public int getSerialNumber() {
  return serialNumber;
 }
}
4

2 回答 2

4

问题是您正在使用 queue.notify() ,它只会唤醒等待队列的单个线程。想象一下,Producer 1 调用 notify() 并唤醒 Producer 2。Producer 2 看到队列中有东西,所以他没有生产任何东西,只是回到 wait() 调用。现在你的生产者和消费者都在等待通知,没有人在工作来通知任何人。

要解决代码中的问题,请使用 queue.notifyAll() 唤醒在 wait() 中阻塞的每个线程。这将允许您的消费者运行。

请注意,您的实现将队列限制为最多包含一个项目。所以你不会从第二组生产者和消费者中看到任何好处。为了更好的实现,我建议您查看BlockingQueue并使用可以有界的实现,例如ArrayBlockingQueue。无需同步和使用等待/通知,只需使用BlockingQueue.offer()BlockingQueue.take()即可。

于 2010-06-18T07:52:37.960 回答
1

而不是 queue.notify() 使用 queue.notifyAll()

于 2010-06-18T07:52:07.970 回答