1. ホーム
  2. java

[解決済み] ExecutorCompletionService? invokeAll があるのに、なぜ必要なのですか?

2022-02-18 01:41:23

質問

を使用する場合 エグゼキュータコンプリートサービス として、一連のタスクを送信することができます。 Callable と対話しながら結果を得ることができます。 CompletionService として queue .

しかし、そこには invokeAllExecutorService を受け付ける。 Collection のリストが得られます。 Future を使用して結果を取得します。

私の知る限り、どちらを使っても利点はありません。 for ループを使用し invokeAll にしなければならないことを submit へのタスクは CompletionService ) と、本質的には同じ考えですが、若干の違いがあります。

では、なぜ一連のタスクの投入に2種類の方法があるのでしょうか?性能的には同等ということでいいのでしょうか?一方が他方より適しているケースはあるのでしょうか?思いつきません。

解決方法は?

を使用することで ExecutorCompletionService.poll/take を受信していることになります。 Future を完了順に(多かれ少なかれ)表示します。使用方法 ExecutorService.invokeAll すべて完了するまでブロックするか、タイムアウトを指定して未完了をキャンセルする必要があります。


static class SleepingCallable implements Callable<String> {

  final String name;
  final long period;

  SleepingCallable(final String name, final long period) {
    this.name = name;
    this.period = period;
  }

  public String call() {
    try {
      Thread.sleep(period);
    } catch (InterruptedException ex) { }
    return name;
  }
}

さて、以下では、どのように invokeAll が動作します。

final ExecutorService pool = Executors.newFixedThreadPool(2);
final List<? extends Callable<String>> callables = Arrays.asList(
    new SleepingCallable("quick", 500),
    new SleepingCallable("slow", 5000));
try {
  for (final Future<String> future : pool.invokeAll(callables)) {
    System.out.println(future.get());
  }
} catch (ExecutionException | InterruptedException ex) { }
pool.shutdown();

これにより、次のような出力が得られます。

C:\dev\scrap>java CompletionExample
... after 5 s ...
quick
slow


使用方法 CompletionService のように、異なる出力が表示されます。

final ExecutorService pool = Executors.newFixedThreadPool(2);
final CompletionService<String> service = new ExecutorCompletionService<String>(pool);
final List<? extends Callable<String>> callables = Arrays.asList(
    new SleepingCallable("slow", 5000),
    new SleepingCallable("quick", 500));
for (final Callable<String> callable : callables) {
  service.submit(callable);
}
pool.shutdown();
try {
  while (!pool.isTerminated()) {
    final Future<String> future = service.take();
    System.out.println(future.get());
  }
} catch (ExecutionException | InterruptedException ex) { }

これにより、次のような出力が得られます。

C:\dev\scrap>java CompletionExample
... after 500 ms ...
quick
... after 5 s ...
slow

時間は、前のメッセージではなく、プログラム開始からの相対時間であることに注意してください。


完全なコードは、両者で確認することができます。 ここで .