My Produce Consumer Hangs - PullRequest
       9

My Produce Consumer Hangs

2 голосов
/ 18 июня 2010

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

Ответы [ 2 ]

4 голосов
/ 18 июня 2010

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

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

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

1 голос
/ 18 июня 2010

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

...