![](/img/trans.png)
[英]Multiple Producer and Consumer Multithreading Java Not Working as Intended
[英]Multiple Producer Multiple Consumer Multithreading Java
我正在嘗試多生產者 - 生產者 - 消費者問題的多個消費者使用案例。 我正在使用BlockingQueue在多個生產者/消費者之間共享公共隊列。
以下是我的代碼。
制片人
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
private BlockingQueue inputQueue;
private static volatile int i = 0;
private volatile boolean isRunning = true;
public Producer(BlockingQueue q){
this.inputQueue=q;
}
public synchronized void run() {
//produce messages
for(i=0; i<10; i++)
{
try {
inputQueue.put(new Integer(i));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Produced "+i);
}
finish();
}
public void finish() {
//you can also clear here if you wanted
isRunning = false;
}
}
消費者
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable {
private BlockingQueue inputQueue;
private volatile boolean isRunning = true;
private final Integer POISON_PILL = new Integer(-1);
Consumer(BlockingQueue queue) {
this.inputQueue = queue;
}
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(!inputQueue.isEmpty()) {
try {
Integer queueElement = (Integer) inputQueue.take();
System.out.println("Consumed : " + queueElement.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Queue ");
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void finish() {
//you can also clear here if you wanted
isRunning = false;
inputQueue.add(POISON_PILL);
}
}
測試類
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ProducerConsumerService {
public static void main(String[] args) {
//Creating BlockingQueue of size 10
BlockingQueue queue = new ArrayBlockingQueue(10);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
//starting producer to produce messages in queue
new Thread(producer).start();
//starting producer to produce messages in queue
new Thread(producer).start();
//starting consumer to consume messages from queue
new Thread(consumer).start();
//starting consumer to consume messages from queue
new Thread(consumer).start();
System.out.println("Producer and Consumer has been started");
}
}
運行以下代碼時,我看不到正確的輸出。
我在這里做錯了嗎?
你的代碼中有相當一部分沒有意義。 我建議你坐下來弄清楚為什么代碼在那里以及它在做什么。
如果刪除了isFinshed
標志,則不會發生任何變化。
如果您在生產者中刪除了synchronized
的使用,那么您將擁有並發生產者。 創建僅在同步塊volatile中訪問的字段沒有任何好處。
對於生產者來說,共享循環計數器是沒有意義的,如果它們是並發的。 通常,生產者發送毒丸,而消費者不會消費葯丸。 例如,如果你有兩個消費者,一個可能會添加葯丸,另一個可能會消耗它。 您的消費者會忽略毒丸,因為它會忽略isFinished
標志。
您不希望僅因為隊列暫時為空而停止使用者。 否則它將不會看到生產者產生的所有消息,可能沒有消息。
包含多個生產者和多個消費者的示例代碼
import java.util.concurrent.*;
public class ProducerConsumerDemo {
public static void main(String args[]){
BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>();
Thread prodThread1 = new Thread(new Producer(sharedQueue,1));
Thread prodThread2 = new Thread(new Producer(sharedQueue,2));
Thread consThread1 = new Thread(new Consumer(sharedQueue,1));
Thread consThread2 = new Thread(new Consumer(sharedQueue,2));
prodThread1.start();
prodThread2.start();
consThread1.start();
consThread2.start();
}
}
class Producer implements Runnable {
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) {
this.threadNo = threadNo;
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
for(int i=1; i<= 5; i++){
try {
int number = i+(10*threadNo);
System.out.println("Produced:" + number + ":by thread:"+ threadNo);
sharedQueue.put(number);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) {
this.sharedQueue = sharedQueue;
this.threadNo = threadNo;
}
@Override
public void run() {
while(true){
try {
int num = sharedQueue.take();
System.out.println("Consumed: "+ num + ":by thread:"+threadNo);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
輸出:
Produced:11:by thread:1
Produced:21:by thread:2
Produced:22:by thread:2
Produced:23:by thread:2
Produced:24:by thread:2
Produced:25:by thread:2
Consumed: 11:by thread:1
Consumed: 22:by thread:1
Consumed: 23:by thread:1
Consumed: 24:by thread:1
Consumed: 25:by thread:1
Produced:12:by thread:1
Consumed: 21:by thread:2
Consumed: 12:by thread:1
Produced:13:by thread:1
Produced:14:by thread:1
Produced:15:by thread:1
Consumed: 13:by thread:2
Consumed: 14:by thread:1
Consumed: 15:by thread:2
本文提供了BlockingQueue的簡單示例生產者和消費者問題
您的代碼更改:
您可以在以下位置找到ExecutorService
替代解決方案:
直接實施它並不太難。 下面的示例代碼就是這樣做的。 它只是將本地變量用於不應該共享的所有內容。
除隊列外,只共享一個保持活動生成器數量的線程安全計數器。 使用計數器而不是特殊的“ POISON_PILL
”值,因為這樣的標記值不適用於單個隊列和多個消費者,因為所有消費者必須識別生產者的完成但僅在所有生產者完成時。
計數器是一個簡單的結束條件。 唯一需要注意的是,在檢測到計數器達到零之后,必須重新檢查隊列以避免競爭條件。
作為旁注,使用Java 5提供的並發功能並且不使用Generics來實現干凈的類型安全代碼是沒有意義的。
final AtomicInteger activeProducers=new AtomicInteger();
final BlockingQueue<Integer> queue=new ArrayBlockingQueue<>(10);
Runnable producer=new Runnable() {
public void run() {
try {
for(int i=0; i<10; i++) {
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
queue.put(i);
System.out.println("Produced "+i);
}
} catch(InterruptedException ex) {
System.err.println("producer terminates early: "+ex);
}
finally { activeProducers.decrementAndGet(); }
}
};
Runnable consumer=new Runnable() {
public void run() {
try {
for(;;) {
Integer queueElement = queue.poll(1, TimeUnit.SECONDS);
if(queueElement!=null)
System.out.println("Consumed : " + queueElement);
else if(activeProducers.get()==0 && queue.peek()==null) return;
}
} catch(InterruptedException ex) {
System.err.println("consumer terminates early: "+ex);
}
}
};
final int NUM_PRODUCERS = 2, NUM_CONSUMERS = 2;
for(int i=0; i<NUM_PRODUCERS; i++) {
activeProducers.incrementAndGet();
new Thread(producer).start();
}
for(int i=0; i<NUM_CONSUMERS; i++) {
new Thread(consumer).start();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.