2011-10-29 53 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()的性能損失在大多數情況下可忽略的,通常並不需要不同的編碼,因爲每個線程等待有虛假喚醒做好準備呢。