英文:
How to wait for main Thread until asynchronous methods will finish?
问题
我有一个带有 `start()` 方法的 **Service.class**:
public void start() {
for (int i = 0; i < companiesList.size(); i++) {
asychronous.someAsynchronous(...);
}
log.info("开始方法已完成");
}
我有一个带有 `someAsynchronous()` 方法的 **Asynchronous.class**:
@Async("threadPoolTaskExecutor")
public CompletableFuture<Void> someAsynchronous(some_parameters) {
//做一些事情
return null;
}
`log.info()` 在 `someAsynchronous()` 方法完成之前就已经出现。
如何强制它等待 `log.info()` 直到循环中的 `someSynchronous()` 方法完成?顺便说一下:异步线程在循环完成后仍然在运行。
英文:
I have Service.class with start()
method:
public void start() {
for (int i = 0; i < companiesList.size(); i++) {
asychronous.someAsynchronous(...);
}
log.info("Start method has finished");
}
I have Asynchronous.class with someAsynchronous()
method:
@Async("threadPoolTaskExecutor")
public CompletableFuture<Void> someAsynchronous(some_parameters) {
//do some stuff
return null;
}
The log.info()
shows up before someAsynchronous()
methods has finished.
How to force it to wait for log.info()
until someSynchronous()
methods in loop will finish? Btw: Asynchronous threads are still running after finishing loop.
答案1
得分: 2
The CompletableFuture<Void>
调用被请求执行,但在它们全部在单独的线程中启动之后,for 循环就完成了,并且日志甚至在它们任何一个完成之前就被打印出来了。这就是异步处理的优势 - 你不关心它们的结果以及执行所花费的时间。
为了实现你想要的效果,你必须定期检查是否 所有 的执行都已完成,然后再继续进行日志输出。
// 添加执行到列表
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < companiesList.size(); i++) {
futures.add(asychronous.someAsynchronous(...));
}
// 定期检查
Iterator<CompletableFuture<Void>> iterator = futures.iterator();
while (iterator.hasNext()) {
CompletableFuture<Void> future = iterator.next(); // 获取下一个
if (future.isDone()) { // 如果已完成...
//... // ... 执行一个动作
iterator.remove(); // ... 并从迭代器中移除
}
if (!iterator.hasNext()) { // 如果到达末尾
iterator = futures.iterator(); // ... 重新遍历剩余的 Futures
}
}
log.info("方法已完成");
注意,这个方法在 所有 执行完成之前不会结束。
编辑:感谢 @Kayaman 提出使用一个单独的 方法 来代替整个 Iterator
逻辑。futures
必须是一个数组:
// 添加执行到列表
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < companiesList.size(); i++) {
futures.add(asychronous.someAsynchronous(...));
}
// 等待所有线程完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
log.info("方法已完成");
英文:
The CompletableFuture<Void>
calls are requested to be executed but after all of them start in separate threads, the for-loop finishes and the log is printed even before any of them finished. This is the advantage of the asynchronous processing - you don't care about their results and how much time they took to execute.
To achieve you want, you have to periodically check whether all of them are finished before you proceed to the log outoput.
// Adds executions to the List
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < companiesList.size(); i++) {
futures.add(asychronous.someAsynchronous(...));
}
// Periodical check
Iterator<CompletableFuture<Void>> iterator = futures.iterator();
while (iterator.hasNext()) {
CompletableFuture<Void> future = iterator.next(); // get the next one
if (future.isDone()) { // if finished...
//... // ... do an action
iterator.remove(); // ... and remove from the Iterator
}
if (!iterator.hasNext()) { // if you reach the end
iterator = futures.iterator(); // ... repeat the remaining Futures
}
}
log.info("Start method has finished");
Note this method doesn't finish until all of the executions are done.
Edit: Thanks to @Kayaman who suggested using a single method dedicated for that replacing the whole Iterator
logics. The futures
must be an array:
// Adds executions to the List
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < companiesList.size(); i++) {
futures.add(asychronous.someAsynchronous(...));
}
// Join the completion of all the threads
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
log.info("Start method has finished");
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论