簡體   English   中英

Java - 多隊列生產者消費者

[英]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 的LockCondition對象,然后使用signal方法

所以每當生產者有數據時,它應該調用signallAll

Lock fileLock = new ReentrantLock();
Condition condition = fileLock.newCondition();
...
// producer has to signal
condition.signalAll();
...
// consumer has to await.
condition.await();

這樣,只有在提供信號時,消費者才會去檢查隊列。

我按照@Abe 的建議解決了類似的情況,但最終決定將SemaphoreAtomicBoolean結合使用,並將其稱為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM