2013-04-20 135 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