Java 多监视器阻塞队列设计

Java 多监视器阻塞队列设计,java,synchronization,blocking,monitor,java.util.concurrent,Java,Synchronization,Blocking,Monitor,Java.util.concurrent,我正在写一个BlockingQueue,我想知道其他实现如何解决这个问题: 如果我只有一个监视器(队列对象)并让生产者和消费者等待,我将必须确保调用notifyAll,而不是notify,否则生产者可能只会通知另一个等待生产者继续,即使队列已满。让消费者等待,即使物品可用。另一方面,调用notifyAll对于许多线程和处理器来说似乎不是一个可伸缩的解决方案 BlockingQueues是否使用两个监视器?一个是生产者等待,一个是消费者等待?然后我必须以封装的方式同步队列和相关监视器。这就是方法吗

我正在写一个BlockingQueue,我想知道其他实现如何解决这个问题:

如果我只有一个监视器(队列对象)并让生产者和消费者等待,我将必须确保调用
notifyAll
,而不是
notify
,否则生产者可能只会通知另一个等待生产者继续,即使队列已满。让消费者等待,即使物品可用。另一方面,调用
notifyAll
对于许多线程和处理器来说似乎不是一个可伸缩的解决方案


BlockingQueue
s是否使用两个监视器?一个是生产者等待,一个是消费者等待?然后我必须以封装的方式同步队列和相关监视器。这就是方法吗?

我不确定在
阻塞队列中是如何做到的,但一种可能的解决方案是使用而不是
同步的

它与syncrhonized
具有相同的语义,但提供了一些改进。特别是,它可能具有其他线程可以等待的几个条件:

public class MyBlockingQueue<E> {
    private Lock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    public void put(E e) {
        lock.lock();
        try {
            while (isFull()) notFull.await();
            boolean wasEmpty = isEmpty();
            ...
            if (wasEmpty) notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public E take() {
        lock.lock();
        try {
            while (isEmpty()) notEmpty.await();
            boolean wasFull = isFull();
            ...
            if (wasFull) notFull.signal();
            ...
        } finally {
            lock.unlock();
        }
    }
    ...
}
公共类MyBlockingQueue{
private Lock=new ReentrantLock();
私有条件notEmpty=lock.newCondition();
private Condition notFull=lock.newCondition();
公众作废认沽权证(E){
lock.lock();
试一试{
while(isFull())notFull.wait();
布尔值为空=为空();
...
if(waspendy)notEmpty.signal();
}最后{
lock.unlock();
}
}
公共电子商务{
lock.lock();
试一试{
while(isEmpty())notEmpty.wait();
布尔值wasFull=isFull();
...
if(wasFull)notFull.signal();
...
}最后{
lock.unlock();
}
}
...
}

通常,与
notify()
相比,使用
notifyAll()
是更好的方法。正如您所提到的,您可以使用两个监视器对象,一个用于读取,另一个用于写入访问。

相反,使用
notify()
可能容易出错,在大多数情况下,使用
notifyAll()
的性能损失是可以忽略的,通常不需要不同的编码,因为每个等待的线程都必须为虚假唤醒做好准备

我想您已经看过中阻塞队列的实现了吗?谢谢,不,我可以看看吗?下载并安装任何Java SDK>=5.0,然后找到文件“src.zip”,其中包含标准Java API的源代码。如果使用eclipse,您可能希望将此文件作为“源文件”附加到“rt.jar”库中,以便于导航和访问源文件和JavaDoc。谢谢,这看起来不错。我刚刚检查了LinkedBlockingQueue,它使用了相同的技术,但是有两个锁(put和take)。这是一个性能提升,还是他们为什么有两个锁?@Franz:是的,他们对两个锁进行了一些优化,如评论中所述<但是,code>ArrayBlockingQueue
使用的是一个锁,如上所示。