1

ExecutorCompletionService を使用していくつかのタスクを送信しています。次に、最大、たとえば 5 秒待ってから、処理を停止します。

ExecutorService executorService = Executors.newFixedThreadPool(10);     
CompletionService<String> completionService = new ExecutorCompletionService<String>(
            executorService);
List<Callable<String>> callables = createCallables(); //each callable sleeps randomly between 1-10 seconds and then prints the thread name
for (Callable<String> callable : callables) 
    taskCompletionService.submit(callable);
for (int i = 0; i < callables.size(); i++) {
    Future<String> result = completionService.take();   
    System.out.println(result.get()); 
}

すべてのタスクが完了するまで 5 秒以上待ちたくありません。5 秒以内に完了したタスクの結果を収集したいだけです。どうすればそれを達成できますか?

executorService.shutdown();
executorService.awaitTermination(5, TimeUnit.SECONDS);

shutdownawaitTerminationonを使用しましexecutorServiceたが、メイン スレッドは送信されたすべてのタスクが完了するまで待機し、すべてのタスクが完了するまでに 10 秒かかり、各スレッドの名前を出力します。5 秒で処理を停止するにはどうすればよいですか?

4

1 に答える 1

0

あなたが言及したように、ここでの主な問題は、コードがshutdown()呼び出される前にタスクが完了するのを待っていることです。基本的にこれはCompletionService.take()、タスクが完了するまでブロックされるためです。さらに、タスクの結果を取得するのにかかった累積時間を追跡する必要がありCompletionServiceます。

代わりに使用しpoll(long, TimeUnit)、結果をタイムアウトの有効期限として解釈しnull、その後すぐにエグゼキュータ サービスをシャットダウンできるという考え方です。これは、たとえば次のように行うことができます。

try {
  ExecutorService executorService = Executors.newFixedThreadPool(10);     
  CompletionService<String> completionService = new ExecutorCompletionService<>(executorService);
  // each callable sleeps randomly between 1-10 seconds and then prints the thread name
  List<Callable<String>> callables = createCallables();
  for (Callable<String> callable : callables) {
    completionService.submit(callable);
  }
  final long timeout = 5_000_000_000L; // 5 seconds in nanos
  long elapsed = 0L;
  int count = 0;
  final long start = System.nanoTime();
  // while not timed out and not all tasks have completed
  while (((elapsed = System.nanoTime() - start) < timeout) && (count < callables.size())) {
    // wait for at most the remaining time before timeout
    Future<String> result = completionService.poll(timeout - elapsed, TimeUnit.NANOSECONDS);
    if (result == null) {
      System.out.println("timed out after " + count + " tasks and " + ((System.nanoTime() - start)/1_000_000L) + " ms");
      break;
    }
    count++;
    System.out.println(result.get()); 
  }
  executorService.shutdownNow();
  System.out.println("done");
} catch (Exception e) {
  e.printStackTrace();
}

createCallables()次のように実装して動作することをテストできました。

private static List<Callable<String>> createCallables() {
  Random rand = new Random(System.nanoTime());
  List<Callable<String>> list = new ArrayList<>();
  for (int i=0; i<10; i++) {
    // between 1 and 10s
    final long time = 1000L * (1L + rand.nextInt(10));
    list.add(new Callable<String>() {
      @Override
      public String call() throws Exception {
        Thread.sleep(time);
        return "ok after " + time + "s on thread " + Thread.currentThread();
      }
    });
  }
  return list;
}
于 2015-09-27T07:29:32.057 に答える