2013-04-20 140 views
0

我正在阅读一本名为“Beginning Algorithms”的书,它有Java中的示例。在关于队列的章节中,它解释了“阻塞队列”,并且......即使当我的背景是C#而不是Java时,对我来说有些东西很有趣。Java中的阻塞队列

这是部分的代码(我省略非相关部分):

public void enqueue(Object value){ 
    synchronized(_mutex){ 
     while(size == _max_size){ 
      waitForNotification(); 
     } 
     _queue.enqueue(value); 
     _mutex.notifyAll(); 
    } 
} 

private void waitForNotification(){ 
    try { 
     _mutex.wait(); 
    } catch(InterruptedException e){ 
     // Ignore 
    } 
} 

public Object dequeue() throws EmptyQueueException { 
    synchronized(_mutex){ 
     while(isEmpty()){ 
      waitForNotification(); 
     } 
     Object value = _queue.dequeue(); 
     _mutex.notifyAll(); 
     return value; 
    } 
} 

我看到了两个主要问题。

首先,如果队列满了,5个线程正在等待添加项目,其他线程出列1个项目,其他5个将被释放,同时会检查“size()== _max_size”是不再真实,他们会尝试调用“_queue.enqueue”5次,使队列溢出。

其次,“出列”同样如此。如果有几个线程因为队列为空而试图将队列出队时被阻塞,添加一个线程将导致他们全部检查队列不再为空,并且所有队列都将试图出队,获得空值或我认为是异常。

对吗?我C#有一个“Monitor.Pulse”,只发布一个阻塞的线程,这是解决方案吗?

干杯。

+4

即使您的所有五个假设线程都可能在notifyAll()后唤醒,但只有一个线程将获取_mutex并输入synchronized块。其余的将回到睡眠状态(编辑:仍在等待进入同步块) – wobbals 2013-04-20 22:37:10

+1

看起来像你的(幻数)5个线程正在使用相同的队列,所以实现是说让其他对象等待一个线程正在添加或删除队列中的元素。 – 2013-04-20 22:37:36

+0

如果5个线程在“_mutex.wait()”中被阻塞,如果我调用“_mutex.notifyAll()”,它们已经在同步块内,只有一个线程会唤醒? – vtortola 2013-04-20 22:43:36

回答

1

您无视​​声明。这只允许一个线程获取_mutex。因此,只有这一个线程将能够检查size的值,因为while语句位于​​块内。

this thread描述的,wait()方法实际上释放_mutex对象和在这种情况下等待呼叫notify(),或notifyAll()。此外,notifyAll()将只授予_mutex一个等待线程的锁定。

+0

我明白了。所以即使当一个线程在“.wait()”中被阻塞时,synchronized语句仍然阻止其他人进入“while”,对吧? – vtortola 2013-04-20 22:46:21

+0

请参阅我上面的编辑。 – 2013-04-20 22:56:40

+0

谢谢。这让我质疑“notify”和“notifyAll”之间的区别,但我已经在SO中得到了答案。干杯。 – vtortola 2013-04-20 23:10:06