Java-多队列生产者消费者
我有以下代码:Java-多队列生产者消费者,java,multithreading,producer-consumer,Java,Multithreading,Producer Consumer,我有以下代码: while(!currentBoard.boardIsValid()){ for (QueueLocation location : QueueLocation.values()){ while(!inbox.isEmpty(location)){ Cell c = inbox.dequeue(location); notifyNeighbours(c.x, c.y,
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
所示)
如何让消费者等待其中一个队列中有东西
我对以下场景有一个问题:假设只有两个队列。消费者检查了第一个,发现它是空的。就在他检查第二个队列(也是空的)时,制作人在第一个队列中放入了一些东西。就消费者而言,队列都是空的,因此他应该等待(即使其中一个不再是空的,他应该继续循环)
编辑:
最后一件事。这是我的练习。我正在尝试自己实现同步。因此,如果任何java库都有实现此功能的解决方案,我对此不感兴趣。我正在努力理解如何实现这一点 如果要跨多个队列进行阻塞,那么一个选项是使用java的 因此,只要生产者有数据,它就应该调用
信号all
Lock fileLock = new ReentrantLock();
Condition condition = fileLock.newCondition();
...
// producer has to signal
condition.signalAll();
...
// consumer has to await.
condition.await();
只有当信号被提供时,消费者才会去检查队列。我按照@Abe的建议解决了一个类似的情况,但决定使用
信号量
和原子布尔
并将其称为二进制信号量。它确实需要修改生产者,以便他们在有事情要做时发出信号。
下面是二进制信号量的代码,以及消费者工作循环的一般概念:
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);
}
}
}
@安倍很接近。我会使用信号和等待-使用对象类内置,因为它们是最轻的重量
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
会释放同步锁定,直到notify-并且需要同步锁定才能成功调用wait方法(它提醒程序员,要使其可靠工作,确实需要某种类型的关键部分)
顺便说一句,如果可行的话,我建议使用专用于消费者(或消费者组)的队列,而不是专用于生产者的队列。它将简化解决方案。除非您可以修改生产者以执行附加信号/通知,否则有两种解决方案,1)使用超时并在cpu消耗和响应性之间找到折衷点,或2)使用附加线程等待队列并通知消费者。第二种方法的附加线程将消耗更多内存,但不会占用大量cpu时间,因为它们大部分都在等待。