Мой потребитель продукции зависает

Скопируйте приведенную ниже программу и попробуйте запустить ее в своей среде 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;
 }
}

person haps10    schedule 18.06.2010    source источник


Ответы (2)


Проблема в том, что вы используете queue.notify(), который разбудит только один поток, ожидающий в очереди. Представьте, что производитель 1 вызывает notify() и будит производителя 2. Производитель 2 видит, что в очереди что-то есть, поэтому он ничего не производит и просто возвращается к вызову wait(). Теперь и ваши производители, и потребители ждут уведомления, и никто не должен работать, чтобы уведомить кого-либо.

Чтобы решить проблему в вашем коде, используйте функцию queue.notifyAll() для пробуждения каждого потока, заблокированного в вызове wait(). Это позволит вашим потребителям работать.

Обратите внимание, что ваша реализация ограничивает очередь наличием не более одного элемента. Таким образом, вы не увидите никакой выгоды от второй группы производителей и потребителей. Для более полной реализации я предлагаю вам взглянуть на BlockingQueue и использовать реализацию, которая может быть ограничена, например, ArrayBlockingQueue. Вместо синхронизации и использования ожидания/уведомления просто используйте BlockingQueue.offer() и BlockingQueue.take().

person Tim Bender    schedule 18.06.2010
comment
Упс... глупый я... наконец-то я могу использовать notifyAll().. Большое спасибо!! - person haps10; 18.06.2010

вместо queue.notify() используйте queue.notifyAll()

person Redlab    schedule 18.06.2010