1. ホーム
  2. java

[解決済み] フューチャーリストの待ち時間

2022-04-14 19:08:53

質問

を返すメソッドがあります。 List 先物の

List<Future<O>> futures = getFutures();

ここで、すべてのフューチャーの処理が正常に終了するか、フューチャーから出力されるタスクのいずれかが例外をスローするまで待ちたいと思います。一つのタスクが例外を投げても、他のfutureを待つ意味はない。

単純な方法としては

wait() {

   For(Future f : futures) {
     try {
       f.get();
     } catch(Exception e) {
       //TODO catch specific exception
       // this future threw exception , means somone could not do its task
       return;
     }
   }
}

しかしここで問題なのは、例えば4番目の未来が例外をスローした場合、最初の3つの未来が利用可能になるまで不必要に待つことになることです。

これを解決するにはどうしたらよいのでしょうか?カウントダウン・ラッチは何か役に立ちますか?私は、Futureを使うことができません。 isDone というのも、javaドキュメントによると

boolean isDone()
Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.

解決方法は?

を使用することができます。 コンプリートサービス を使用して、準備ができ次第先物を受け取り、そのうちのひとつが例外をスローした場合は処理をキャンセルします。このようなものです。

Executor executor = Executors.newFixedThreadPool(4);
CompletionService<SomeResult> completionService = 
       new ExecutorCompletionService<SomeResult>(executor);

//4 tasks
for(int i = 0; i < 4; i++) {
   completionService.submit(new Callable<SomeResult>() {
       public SomeResult call() {
           ...
           return result;
       }
   });
}

int received = 0;
boolean errors = false;

while(received < 4 && !errors) {
      Future<SomeResult> resultFuture = completionService.take(); //blocks if none available
      try {
         SomeResult result = resultFuture.get();
         received ++;
         ... // do something with the result
      }
      catch(Exception e) {
             //log
         errors = true;
      }
}

さらに改良して、まだ実行中のタスクの1つがエラーを投げたらキャンセルするようにしてもいいと思います。