2

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を使用する唯一の方法ですか?

4

1 に答える 1

3

この場合、これは非常に複雑な(そしてエラーが発生しやすい)ソリューションだと思います。一般的なBlockingQueueを使用すると、このブロッキングキューから単一のスレッドがポーリングされ、ExecutorServiceにジョブが渡されます。

この場合、CountDownLatchが必要になる理由はわかりません。これは、ワーカーを不必要に複雑にします。これは、スレッド環境で実行されていることを理解する必要があり、終了時にダーティなものをすべてクリーンアップする必要があります。BlockingQueuesとExecutorServicesは、これらの問題から抜け出すために正確に用意されています。

于 2011-08-15T04:25:03.973 に答える