Domanda

Si prega di copiare il programma qui sotto e provare a eseguire nel vostro IDE. Si tratta di una realizzazione semplice Produrre dei consumatori - funziona benissimo quando uso un produttore e un filo di consumo, ma non riesce quando si utilizza 2 ciascuno. Per favore fatemi sapere il motivo per cui questo programma si blocca o c'è qualcosa che non va con esso.

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;
 }
}
È stato utile?

Soluzione

Il problema è che si sta utilizzando queue.notify () che non farà che svegliare un singolo thread in attesa sulla coda. Imagine Producer 1 chiamate notify () e si sveglia Producer 2. Producer 2 vede che c'è qualcosa in coda in modo che non produce nulla e semplicemente risale alla chiamata wait (). Ora sia i produttori ei consumatori sono tutti in attesa di ricevere un avviso e nessuno viene lasciato al lavoro per avvisare nessuno.

Per risolvere il problema nel codice, utilizzare queue.notifyAll () di svegliarsi ogni Discussione bloccata in un'attesa (). Questo permetterà ai vostri utenti di eseguire.

Come una nota, l'implementazione limita la coda per avere al massimo un elemento in esso. Quindi non si vedrà alcun beneficio dal secondo gruppo di produttori e consumatori. Per una migliore implementazione tutto intorno, vi suggerisco di guardare a BlockingQueue e utilizzare un'implementazione che può essere limitato, per esempio, il ArrayBlockingQueue . Invece di sincronizzazione e l'utilizzo di wait / notify, è sufficiente utilizzare BlockingQueue.offer () e BlockingQueue.take () .

Altri suggerimenti

al posto di queue.notify () uso queue.notifyAll ()

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top