2011-08-15 5 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

Hmm ..だから、ExecutorServiceが唯一の方法だと思います。私がCountDownLatchを使用している理由は、実際には のようなものを実行する予定です。while(未完了){3つのスレッドを作成して実行} ' だから、すべてのスレッドが実際に作業を完了してから次のステップ – GantengX

+0

タスクを実行するときにスレッドが失敗した場合、ExecutorServiceはタスクを別のスレッドに渡すことができますか? – GantengX

+0

Callableを使用して未来のものを入手し、回答が来るのを待って、簡単にタイムアウトすることもできます。 –