2012-05-15 153 views
0

n個線程產生到BlockingQueue。 當隊列已滿時,消費者會排空隊列並執行一些處理。阻塞隊列設計

我應該如何決定以下兩種實施方式?

選擇A: 消費者定期輪詢隊列以檢查它是否已滿,所有寫入者正在等待(畢竟這是一個阻塞隊列:)。

選擇B: 我使用同步的「put」方法實現自己的隊列。在放置提供的元素之前,我測試隊列是否接近滿(全部減1元素)。然後,我把這個元素,並通知我的消費者(正在等待)。

第一種解決方案是最簡單的方法,但可以進行輪詢;這讓我很煩惱。 第二種解決方案在我看來更容易出錯,更多需要更多編碼。

+2

您還可以使用其他方式來溝通「開始處理」,例如, CountdownLatch。此外,爲什麼消費者不能只獲取所有元素,並決定何時自行開始處理它們(例如在擁有N個元素之後?) –

+0

然後,我的消費者會消耗所有元素,並在達到特定數量時元素,他處理它們。 在這種情況下,他會一直工作,並試圖達到極限 我喜歡那個:)我會試試看看它是如何工作的... –

回答

0

第二種解決方案顯然更好。它並不複雜。您可以繼承或包裝任何其他BlockingQueue並覆蓋其方法offer(),如下所示:調用「真實」offer()。如果返回true,請退出。否則,請觸發工作線程工作,並立即通過超時時間呼叫offer()

這裏是幾乎僞代碼:

public boolean offer(E e) { 
    if (queue.offer(e)) { 
     return true; 
    } 
    boolean result = queue.offer(e, timeout, unit); // e.g. 20 sec. - enough for worker to dequeue at least one task from the queue, so the place will be available. 
    worker.doYouJob(); 
    return result; } 
+0

我想到了那個,但是在返回false的第一個offer和我的第二個「offer」之間,我可能會再次被卡住,因爲有其他線程可能會填滿我的隊列。 –

0

我不知道有沒有這樣的實現需要隊列:消費者是等待,而隊列已滿,只有當它完全排出,並開始處理。

您的排隊應該被阻止消費者,直到它變滿。認爲您需要重寫drain()方法,使其在隊列變滿時等待。比你的消費者只是打電話等排水法。不需要從生產者到消費者的通知。

0

使用觀察者模式。讓您的消費者註冊隊列通知器。當一個生產者執行放置時,隊列將決定是否通知任何監聽者。

2

我會建議編寫你的代理隊列,它將在內部與一個Exchanger實例一起包裝一個隊列實例。您的代理方法將調用委託給您的內部隊列。檢查添加內部隊列時是否已滿,當內部隊列已滿時,將內部隊列與消費者線程交換。消費者線程將交換一個空隊列作爲對填充隊列的回報。您的代理隊列將繼續填充空隊列,而消費者可以繼續處理已填充的隊列。這兩項活動可以並行運行。當雙方準備好後,他們可以再次交換。

class MyQueue implements BlockingQueue{ 
    Queue internalQueue = ... 
    Exchanger<Queue> exchanger; 

    MyQueue(Exchanger<BlockingQueue> ex){ 
    this.exchanger = ex; 
    } 

    . 
    . 
    . 

    boolean add (E e) { 
     try{ 
     internalQueue.add(e); 
     }catch(IllegalStateException ise){ 
     internalQueue = exchanger.exchange(internalQueue); 
     } 
     internalQueue.add(e);  
    } 

} 

class Consumer implements Runnable { 
    public void run() { 
     Queue currentQueue = new empty queue; 
     while (...){ 
      Object o = currentQueue.remove(); 
      if (o == null){ 
       currentQueue = exchanger.exchange(currentQueue); 
       continue; 
      } 
      //cast and process the element 
     } 
    } 
} 
+0

你是否建議使用Exceptions來控制流程?這通常是一個糟糕的主意,並且令人不悅。 – Brady

+0

代碼僅僅是指示性的,不打算提供實現,只是爲了給出一個想法。但是,你說得對! – Drona

+0

我喜歡這個有2個隊列的選項,我最近在C++嵌入式環境中使用它,它真的減少了生產者和消費者之間的鎖定爭用。在添加到隊列中時,我做了一個簡單的檢查,而不是例外情況。 – Brady

0

我用了CountdownLatch,它很簡單,效果很好。 感謝您的其他想法:)