我已获得以下代码:
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库都有一个实现这个的解决方案,我对它不感兴趣。我试图了解如何实现这一点。
答案 0 :(得分:1)
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
释放同步锁,直到通知 - 并且需要锁定同步才能成功调用wait方法(它提醒程序员某些类型的关键部分确实是这需要可靠的工作)。
顺便说一下,如果可行的话,我会建议一个专用于消费者(或消费者群体)的队列,而不是专用于生产者的队列。它将简化解决方案。
答案 1 :(得分:0)
如果要阻止多个队列,则可以选择使用java Lock
and Condition
objects and then use the signal
method。
因此,只要生产者有数据,它就应该调用signallAll
。
Lock fileLock = new ReentrantLock();
Condition condition = fileLock.newCondition();
...
// producer has to signal
condition.signalAll();
...
// consumer has to await.
condition.await();
这种方式只有在提供信号时,消费者才会去检查队列。
答案 2 :(得分:0)
我解决了与@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);
}
}
}