什么是等待可完成的未来线程完成的推荐方法

时间:2015-06-08 09:50:25

标签: java multithreading concurrency completable-future

我在代码中使用CompletableFuture,如下所示。但关于我应该等到所有可运行完成的方式,我找到了两种方法,我不知道它们之间的区别,哪一种是最佳实践?它们如下:

代码

this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor);

等待所有runnables完成的第一种方法

this.growSeedExecutor.shutdown();
this.growSeedExecutor.awaitTermination(1, TimeUnit.DAYS);

等待所有runnables完成的第二种方法

CompletableFuture.allOf(this.growSeedFutureList).join();

请让我知道推荐哪一个。

2 个答案:

答案 0 :(得分:8)

仅当执行程序(growSeedExecutor)仅用于给定任务时,两种方式都是等效的。第一种方式可能导致以下:另一个任务需要并行化,并为每个任务创建新的执行程序。一些开发人员看到创建了太多执行程序,并决定使用单个通用执行程序,但未能删除所有执行程序关闭...

所以第二种方式(join())更可靠,因为它不那么复杂。但是每个新的未来都应该添加到growSeedFutureList中,而不是分配给。

答案 1 :(得分:5)

如果您真的想等待所有期货,只需在每个期货上致电join()

growSeedFutureList.forEach(CompletableFuture::join);

与使用allOf()相比,主要区别在于,一旦到达具有异常的未来,它将抛出异常,而allOf().join()版本只会在所有期货之后抛出异常完成(特殊与否)。

另一个小差异是,这不会创建中间allOf阶段。如果您想在所有期货完成后异步执行某些操作,而不是等待所有期货完成,那么此阶段仍然有用。

另一方面执行者的解决方案有几个缺点:

  • 它阻止重用执行程序,因为它需要关闭;
  • 它要求您对所有操作使用该执行程序 - 它不适用于以其他方式管理的CompletableFuture;
  • 它没有清楚地表明你的意图,即等待所有的期货完成;
  • 实施起来比较复杂;
  • 它不处理异常完成 - awaitTermination()如果其中一个任务失败,则不会抛出任何异常。