ラッチ、バリア、セマフォなどのより複雑な同期メカニズムを使用できますが、を参照してくださいExecutorCompletionService
。これは軽量のラッパーであり、最初に完了したタスクExecutorService
をリッスンできます。簡単な例を次に示します。
final ExecutorService executorService = Executors.newCachedThreadPool();
final ExecutorCompletionService<String> completionService =
new ExecutorCompletionService<String>(executorService);
for (int i = 0; i < 10; ++i) {
completionService.submit(new Task());
}
completionService.take().get();
コードは非常に単純です。まず、でラップexecutorService
しcompletionService
ます。後でそれを使用して、タスクを次々に送信します。最後の行は非常に重要です。終了した最初のタスクを取得し、結果を取得しようとします。例外がスローされた場合は、ここで再スローされ、次のようにラップされExecutionException
ます。
try {
completionService.take().get();
} catch (ExecutionException e) {
e.getCause(); //this was thrown from task!
}
ブロック内catch
では、残りのタスクをキャンセルしたり、スレッドプール全体をシャットダウンしたりするなど、なんらかの方法で例外を処理できます。
もちろん、take()
10回呼び出すことで、すべてのタスクが完了するのを自由に待つことができます。少なくとも1つのタスクが終了している限り、各呼び出しはブロックされます。