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

我正在使用如下代码所示。但是关于我应该等到所有runnables完成的方式,我发现了两种方法,我不知道它们之间的区别,哪一个是最佳实践?它们如下所示: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);

等待所有可运行项完成的第一种方法

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

第二种等待所有可运行项完成的方法

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

请让我知道哪一个是推荐的。


答案 1

如果您真的想等待所有期货,您可以简单地调用每个期货:join()

growSeedFutureList.forEach(CompletableFuture::join);

与使用相比,主要区别在于,一旦达到具有异常的未来完成,这将立即引发异常,而版本仅在所有期货完成后(异常或非异常)才会引发异常。allOf()allOf().join()

另一个小小的区别是,这不会产生中间阶段。如果您想在所有期货完成后异步执行某些操作,而不仅仅是等待所有期货完成,这样的阶段仍然很有用。allOf

另一侧执行器的解决方案有几个缺点:

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

答案 2

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

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


推荐