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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30705981/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:02:18  来源:igfitidea点击:

What is the recommended way to wait till the Completable future threads finish

javamultithreadingconcurrencycompletable-future

提问by user2121

I am using CompletableFutureas shown below in the code. But concerning the way I should wait till all runnables finish, I found two ways and I do not know the difference between them and which one is the best practice? They are as follows:

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

Code:

代码

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);

First approach to wait till all runnables finish:

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

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

Second approach to wait till all runnables finish:

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

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

Please let me know which one is recommended.

请告诉我推荐哪一个。

采纳答案by Alexei Kaigorodov

Both ways are equivalent only when the executor (growSeedExecutor) is used solely for the given task. The first way may lead to following: Another tasks need parallelization, and new executor is created for each task. Some developer sees too many executors created, and decide to use single common executor, but failed to delete all executor shutdowns...

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

So the second way (join()) is more reliable, since is less complex. But each new future should be added to the growSeedFutureList, not assigned to.

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

回答by Didier L

If you really want to wait on all futures, you can simply call join()on each of them:

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

growSeedFutureList.forEach(CompletableFuture::join);

The main difference compared to using allOf()is that this will throw an exception as soon as it reaches a future completed with an exception, whereas the allOf().join()version will only throw an exception after all futures have completed (exceptionally or not).

与 using 相比的主要区别allOf()在于,这将在到达带有异常的 future 完成后立即抛出异常,而该allOf().join()版本只会在所有future完成(异常与否)后才会抛出异常。

Another small difference is that this does not create the intermediary allOfstage. Such a stage remains useful if you want to do something asynchronously after all futures have completed, instead of just waiting for all of them to complete.

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

The solution with the executor on the other side has several drawbacks:

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

  • it prevents to reuse the executor as it requires its shutdown;
  • it requires you to use that executor for all operations – it will not work with CompletableFutures that are managed in another way;
  • it does not clearly shows your intent, which is to wait for all futures to complete;
  • it is more complex to implement;
  • it does not handle exceptional completion – no exception will be thrown by awaitTermination()if one of the tasks failed.
  • 它阻止重用执行器,因为它需要关闭;
  • 它要求您为所有操作使用该执行程序——它不适CompletableFuture用于以其他方式管理的 s;
  • 它没有明确表明您的意图,即等待所有期货完成;
  • 实施起来比较复杂;
  • 它不处理异常完成——awaitTermination()如果其中一项任务失败,则不会抛出异常。