[英]Java - Multiple queue producer consumer
我有以下代碼:
while(!currentBoard.boardIsValid()){
for (QueueLocation location : QueueLocation.values()){
while(!inbox.isEmpty(location)){
Cell c = inbox.dequeue(location);
notifyNeighbours(c.x, c.y, c.getCurrentState(),previousBoard);
}
}
}
我有一個有幾個隊列的消費者(他們所有的方法都是同步的)。 每個生產者一個隊列。 消費者遍歷所有隊列並檢查他們是否有任務供他消費。 如果他正在檢查的隊列中有一個任務,他就會消耗它。 否則,他會去檢查下一個隊列,直到他完成對所有隊列的迭代。
到目前為止,如果他遍歷所有隊列並且它們都是空的,他會繼續循環而不是等待其中一個包含某些內容(如外部while
所見)。
我怎樣才能讓消費者等到其中一個隊列中有東西?
我遇到以下情況的問題:假設只有 2 個隊列。 消費者檢查了第一個,它是空的。 正如他正在檢查第二個(也是空的)一樣,生產者將一些東西放入第一個隊列中。 就消費者而言,隊列都是空的,所以他應該等待(即使其中一個不再是空的,他應該繼續循環)。
編輯:最后一件事。 這對我來說是一個練習。 我正在嘗試自己實現同步。 因此,如果任何 Java 庫都有實現此功能的解決方案,我對它不感興趣。 我試圖了解如何實現這一點。
@Abe 很接近。 我會使用信號和等待 - 使用內置的 Object 類,因為它們是最輕的。
Object sync = new Object(); // Can use an existing object if there's an appropriate one
// On submit to queue
synchronized ( sync ) {
queue.add(...); // Must be inside to avoid a race condition
sync.notifyAll();
}
// On check for work in queue
synchronized ( sync ) {
item = null;
while ( item == null ) {
// Need to check all of the queues - if there will be a large number, this will be slow,
// and slow critical sections (synchronized blocks) are very bad for performance
item = getNextQueueItem();
if ( item == null ) {
sync.wait();
}
}
}
請注意, sync.wait
釋放同步鎖直到通知 - 並且同步鎖是成功調用等待方法所必需的(它提醒程序員確實需要某種類型的臨界區才能使其可靠地工作)。
順便說一句,如果可行,我會推薦一個專用於消費者(或一組消費者)的隊列,而不是專用於生產者的隊列。 它將簡化解決方案。
如果要跨多個隊列進行阻塞,那么一種選擇是使用 java 的Lock
和Condition
對象,然后使用signal
方法。
所以每當生產者有數據時,它應該調用signallAll
。
Lock fileLock = new ReentrantLock();
Condition condition = fileLock.newCondition();
...
// producer has to signal
condition.signalAll();
...
// consumer has to await.
condition.await();
這樣,只有在提供信號時,消費者才會去檢查隊列。
我按照@Abe 的建議解決了類似的情況,但最終決定將Semaphore
與AtomicBoolean
結合使用,並將其稱為 BinarySemaphore。 它確實需要修改生產者,以便他們在有事情要做時發出信號。
下面是 BinarySemaphore 的代碼以及消費者工作循環應該是什么樣子的一般概念:
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class MultipleProdOneConsumer {
BinarySemaphore workAvailable = new BinarySemaphore();
class Consumer {
volatile boolean stop;
void loop() {
while (!stop) {
doWork();
if (!workAvailable.tryAcquire()) {
// waiting for work
try {
workAvailable.acquire();
} catch (InterruptedException e) {
if (!stop) {
// log error
}
}
}
}
}
void doWork() {}
void stopWork() {
stop = true;
workAvailable.release();
}
}
class Producer {
/* Must be called after work is added to the queue/made available. */
void signalSomethingToDo() {
workAvailable.release();
}
}
class BinarySemaphore {
private final AtomicBoolean havePermit = new AtomicBoolean();
private final Semaphore sync;
public BinarySemaphore() {
this(false);
}
public BinarySemaphore(boolean fair) {
sync = new Semaphore(0, fair);
}
public boolean release() {
boolean released = havePermit.compareAndSet(false, true);
if (released) {
sync.release();
}
return released;
}
public boolean tryAcquire() {
boolean acquired = sync.tryAcquire();
if (acquired) {
havePermit.set(false);
}
return acquired;
}
public boolean tryAcquire(long timeout, TimeUnit tunit) throws InterruptedException {
boolean acquired = sync.tryAcquire(timeout, tunit);
if (acquired) {
havePermit.set(false);
}
return acquired;
}
public void acquire() throws InterruptedException {
sync.acquire();
havePermit.set(false);
}
public void acquireUninterruptibly() {
sync.acquireUninterruptibly();
havePermit.set(false);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.