2011-08-15 73 views
2

我正在考慮如何在Java中實現生產者/消費者模式。Java中的生產者/消費者模式

假設我有3個線程和一個包含任務的列表(說它是關於5個任務)。每個線程從列表中抓取任務並同時執行。我目前的做法是使用CountDownLatch

int N = 3; 
CountDownLatch startSignal = new CountDownLatch(1); 
CountDownLatch doneSignal = new CountDownLatch(N); 
ConcurrentLinkedQueue<String> tasks = new ConcurrentLinkedQueue<String>(); 

main() { 
    for (int i=0;i<N;i++) { 
     new Thread(new Worker()).start(); 
    } 
    startSignal.countDown(); 
    doneSignal.await(); 
    System.out.println("done"); 
} 

class Worker implements Runnable { 
    public void run() { 
     startSignal.await(); 
      while ((s = tasks.poll()) != null) { 
       // do lengthy task here 
       if (task failed) { 
        tasks.add(s); 
        return; // assume that task fails badly and have to stop the thread 
       } 
      } 
     doneSignal.countDown(); 
    } 
} 

什麼,我想實現的是,如果一個線程處理任務失敗時,它會被添加到任務列表,可以通過電流或任何其他線程再度回升,但使用當前使用CountDownLatch的方法顯然不可能這樣做,因爲在調用doneSignal.countDown()之後,線程會假定它已完成任務。

這種情況下最好的方法是什麼?是使用Executor的唯一方法?

回答

3

我想說這是一個過分複雜(並容易出錯)的解決方案,使用通用的BlockingQueue,從這個阻塞隊列中進行單線程輪詢並將作業交給ExecutorService 。

看不出有什麼理由說明爲什麼在這種情況下你需要一個CountDownLatch,它只是不必要地使你的工作變得複雜,必須理解它是在一個線程環境中運行,並且必須清理任何髒的時候飾面。 BlockingQueues和ExecutorServices是否準確地幫助您擺脫這些問題。

+0

嗯..所以我猜ExecutorService是唯一的方法。我使用CountDownLatch的原因是我實際上計劃在執行類似於 'while while(not finished){創建3個線程並執行它們}' '因此我想要確保所有線程在繼續執行下一步 – GantengX

+0

如果一個線程在執行任務時失敗,ExecutorService是否可以將任務傳遞給另一個線程? – GantengX

+0

使用Callable's並獲得Future並等待他們有答案,那麼您甚至可以輕鬆超時。 –