2011-12-18 303 views
0

我有2個主題。塊和喚醒消費者線程/

他們每個人都從共享緩衝區讀取一些數據。

currentDataBuffer.get(thisID); //currentDataBuffer is my shared buffer object 

我要攔截的每個線程每次調用拿到後,並釋放它,當所有線程讀取緩衝區(一次) 所以我用這個currentDataBuffer對象鎖定:

currentDataBuffer.get(thisID); 
synchronized (currentDataBuffer) { 
    currentDataBuffer.wait(); 
} 

問題當所有線程完成從緩衝區讀取(每行一行)時,如何釋放這些線程?

裏面currentDataBuffer我有一個地圖,我存儲從緩衝區中讀取數據的線程的ID。

如何使用this.notifyAll();(來自currentDataBuffer)來喚醒所有鎖定的線程?

回答

0

我建議你使用Java BlockingQueue數據結構。調用BlockingQueue.take()塊直到有元素可用。 因此,而不是:

currentDataBuffer.get(thisID); 
synchronized (currentDataBuffer) { 
    currentDataBuffer.wait(); 
} 

您將有:

currentDataBuffer.take(); 

擋在了take()調用的線程可以通過添加元素到隊列通過調用BlockingQueue.offer(object)方法

+0

我需要一個n線程的緩衝區,只有在所有線程都讀取相同的數據後,我需要移動到緩衝區中的下一個項目。 – kenny 2011-12-18 16:36:50

0

的釋放答案繼續你的代碼可能是使用currentDataBuffer.notifyAll()而不是this.notifyAll()(它不太清楚什麼this引用你的問題)。但是,那麼如何確保在所有線程讀取緩衝區並進入等待狀態之後調用notifyAll

如果您知道應讀取緩衝區的線程數,更好的解決方案是使用兩個CountDownLatch。這個班的javadoc有一個很好的例子。

------------更新:

您不需要更改讀者線程的代碼。您應該將鎖存器放在您的currentDataBuffer對象中。在currentDataBuffer中創建一個線程,等待n項目鎖存。在get方法中,讀數完成後,在該鎖存器上調用CountDownLatch.countDown()。哦,我會寫它:

class CurrentDataBuffer implements Runnable { 

    private CountDownLatch singleThreadFinishedSignal; 
    private CountDownLatch allThreadsFinishedSignal; 

    public CurrentDataBuffer(int N) { 
     singleThreadFinishedSignal = new CountDownLatch(N); // waiter thread waits on this 
     allThreadsFinishedSignal = new CountDownLatch(1); // reader threads wait on this after finished reading 
    } 

    public void run() { 
     try { 
      singleThreadFinishedSignal.await(); // wait for all reader threads to finish 
      allThreadsFinishedSignal.countDown(); // let all reader threads proceed 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void get() { 
     try { 
      // read buffer item here /////////////////// 
      singleThreadFinishedSignal.countDown(); // mark that a thread has read the item 
      allThreadsFinishedSignal.await(); // wait for other reader threads to finish 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

是的,我知道線程的數量。我用這個。currentDataBuffer對象本身內的notifyAll(),這就是爲什麼它是「this」。 – kenny 2011-12-18 17:00:58

+0

我無法使用CountDownLatch,因爲我無法更改(代碼)創建線程 – kenny 2011-12-18 17:02:47

+0

我更新了答案。 – yair 2011-12-18 17:19:33

0

我想的CountDownLatch(http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html)會有所幫助。

I.e.使用初始值爲2的CountDownLatch(或任何想要處理的線程數)來擴充currentDataBuffer。處理線程後調用latch.countDown(),然後latch.await()。

爲了安全起見,您可能要小心countDowns不會丟失(例如,如果拋出異常)。

+0

我無法使用CountDownLatch,因爲我無法更改線程的創建(代碼) – kenny 2011-12-18 17:05:32

+0

您是否有權控制currentDataBuffer的類?如果是這樣,你可以在其get方法中添加countDown()/ await()。 – 2011-12-18 17:10:47

+0

是的,我有currentDataBuffer控件,但爲什麼我應該在那裏等待?消費者線程是那些從緩衝區讀取數據的線程! – kenny 2011-12-18 17:13:45