请复制下面的程序,然后尝试在您的IDE中运行。这是一个简单的农产品消费者实现 - 当我使用一个生产者和一个消费者线程时,它运行良好,但使用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;
 }
}
有帮助吗?

解决方案

问题在于您正在使用queue.notify(),该notify()只会唤醒一个在队列上等待的单个线程。想象一下生产者1呼叫通知()并唤醒生产者2。生产者2看到队列中有东西,因此他没有生产任何东西,然后简单地回到wait()呼叫。现在,您的生产者和消费者都在等待通知,没有人努力通知任何人。

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

注意,您的实施将队列限制在其中最多有一项。因此,您将不会从第二组生产商和消费者那里看到任何好处。为了在实施方面做得更好,我建议您看看 阻塞 并使用实现,例如 Arrayblockingqueue. 。而不是同步和使用等待/通知,只需使用 blockingqueue.offer()blockingqueue.take().

其他提示

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top