2011-10-29 15 views
3

我写一个BlockingQueue的,我想知道其他实现方式是如何解决这个问题:BlockingQueue的设计有多个显示器

如果我只有一个监视器(队列对象),并让生产者和消费者wait,我则要保证notifyAll而不是notify被调用,否则生产者可能只会发信号通知另一个等待的生产者继续,即使队列已满。即使有东西可用,也让消费者等待。另一方面,调用notifyAll似乎不是许多线程和处理器的可伸缩解决方案。

请问BlockingQueue是否使用两台显示器?一个是生产者等待,一个是消费者等待?然后,我将不得不以封装方式同步队列和相关监视器。这是要走的路吗?

+0

我假设你已经有了一起来看看在【JAVA]阻塞队列的实现(http://download.oracle.com/javase/1,5,0/docs/api/java/util/concurrent/BlockingQueue html的)? – JimmyB

+0

谢谢,不,我能看到它吗? –

+1

下载并安装任何Java SDK> = 5.0,找到其中包含源代码的标准Java API的文件“src.zip”。如果使用Eclipse,你可能想将这个文件作为“源文件”附加到轻松导航和获取源代码和Javadoc的“rt.jar中”库。 – JimmyB

回答

5

我不知道它是如何在BlockingQueue做,但一个可能的解决方案是使用ReentrantLock而不是​​。

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

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(); 
     } 
    } 
    ... 
} 
+0

谢谢,这看起来不错。我只是检查的LinkedBlockingQueue并使用相同的技术,但有2个锁(put和take)。这是一个表现助推器,或者他们为什么有两个锁? –

+2

@Franz:是的,他们对两个锁使用了一些优化,如评论中所述。但是,ArrayBlockingQueue完全按照上图所示使用单个锁。 – axtavt

1

一般情况下,使用notifyAll()是比较notify()更好的办法。正如您所提到的,您可以使用两个监视器对象,一个用于读取,一个用于写入访问。
使用notify()反而容易出现错误和使用notifyAll()的性能损失在大多数情况下可忽略的,通常并不需要不同的编码,因为每个线程等待有虚假唤醒做好准备呢。