私の農産物の消費者がぶら下がっています
-
28-09-2019 - |
質問
以下のプログラムをコピーして、IDEで実行してみてください。これは単純な生産の消費者の実装です。1つのプロデューサーと1つの消費者スレッドを使用すると正常に実行されますが、それぞれ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()を使用していることです。プロデューサー1がNotify()を呼び出し、プロデューサー2を目覚めさせることを想像してください。プロデューサー2は、キューに何かがあることを確認しているので、彼は何も生産せず、単に待機()コールに戻ります。現在、生産者と消費者の両方が通知を待っており、誰にも通知するために働いていないままになっています。
コードの問題を解決するには、queue.notifyall()を使用して、wait()でブロックされたすべてのスレッドを起動します。これにより、消費者が実行できます。
メモとして、実装により、キューが最大1つのアイテムを含めることに制限されます。したがって、プロデューサーと消費者の2番目のセットからのメリットは見られません。より良い実装のために、私はあなたが ブロッキングキュー そして、たとえば、制限できる実装を使用してください。 arrayblockingqueue. 。同期して待機/通知を使用する代わりに、単に使用する blockingqueue.offer() と blockingqueue.take().
他のヒント
queue.notify()の代わりにqueue.notifyall()を使用します
所属していません StackOverflow