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时间,因为它们大部分都在等待。