Question

S'il vous plaît copiez le programme ci-dessous et essayez d'exécuter dans votre IDE. Il est un simple Produire la mise en œuvre des consommateurs - il fonctionne très bien quand j'utilise un producteur et un fil à la consommation, mais échoue lorsque vous utilisez 2 chacun. S'il vous plaît laissez-moi savoir la raison pour laquelle ce programme se bloque ou est-il quelque chose de mal d'autre avec elle.

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;
 }
}
Était-ce utile?

La solution

Le problème est que vous utilisez queue.notify () qui ne se réveiller un seul thread en attente sur la file d'attente. Imaginer des appels de producteurs 1 notify () et 2. Le producteur se réveille en Producer 2 voit qu'il ya quelque chose dans la file d'attente afin qu'il ne produit rien et va simplement revenir à l'appel d'attente (). Maintenant, les deux producteurs vos consommateurs et sont en attente d'être informé et personne ne reste travaille à informer tout le monde.

Pour résoudre le problème dans votre code, utilisez queue.notifyAll () pour se réveiller chaque thread bloqué à une attente (). Cela permettra à vos clients de fonctionner.

Comme une note, votre implémentation limite la file d'attente ayant au plus un élément en elle. Donc, vous ne verrez aucun avantage de la deuxième série de producteurs et les consommateurs. Pour une meilleure mise en œuvre de tout autour, je vous suggère de regarder ArrayBlockingQueue . Au lieu de synchronisation et en utilisant attente / notify, utilisez simplement BlockingQueue.offer () et BlockingQueue.take () .

Autres conseils

au lieu de queue.notify () utilisation queue.notifyAll ()

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top