如何等待主线程直到异步方法完成?

huangapple go评论72阅读模式
英文:

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 &lt; companiesList.size(); i++) {
		asychronous.someAsynchronous(...);
	}
	log.info(&quot;Start method has finished&quot;);
}

I have Asynchronous.class with someAsynchronous() method:

@Async(&quot;threadPoolTaskExecutor&quot;)
public CompletableFuture&lt;Void&gt; 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&lt;Void&gt; 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&lt;CompletableFuture&lt;Void&gt;&gt; futures = new ArrayList&lt;&gt;();
for (int i = 0; i &lt; companiesList.size(); i++) {
    futures.add(asychronous.someAsynchronous(...));
}

// Periodical check
Iterator&lt;CompletableFuture&lt;Void&gt;&gt; iterator = futures.iterator();
while (iterator.hasNext()) {
	CompletableFuture&lt;Void&gt; 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(&quot;Start method has finished&quot;);

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&lt;CompletableFuture&lt;Void&gt;&gt; futures = new ArrayList&lt;&gt;();
for (int i = 0; i &lt; companiesList.size(); i++) {
    futures.add(asychronous.someAsynchronous(...));
}

// Join the completion of all the threads
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

log.info(&quot;Start method has finished&quot;);

huangapple
  • 本文由 发表于 2020年4月4日 04:45:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/61020134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定