java - 为什么主线程不等待其他异步进程(线程)完成。allOff 无法正常工作
问题描述
我在 for 循环中调用一个异步方法并将其未来添加到列表中。我不确定为什么 allOff 不等待完成所有期货并返回部分结果。看看我的代码。
我有一种被覆盖的方法
@Overide
@Async
CompletableFuture<someType> fetchData()
{
returns new CompletableFuture<someType>();
}
我在具有不同实例的 for 循环中调用上述方法。
获取所有实现一个具有方法 fetchData 的接口的 bean。
Map<String, SomeClass> allBeans =context.getBeansOfType(SomeClass.class);
List<SomeClass> list=
allBeans.values().stream().collect(SomeClass.toList());
for (SomeClass classInstance: list) {
classInstance.fetchData().thenApply(x->{
//Some DB persistence Call
futureList.add(x);
});
}
之后我应用 allOff 以便可以完成所有未来,但它不是等待所有和主线程执行其余的流程。
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(
futureList.toArray(new CompletableFuture[futureList.size()]));
CompletableFuture<List<futureResponse>> finalList=
combinedFutures.thenApply(v -> {
return futureList.stream().map(m ->
m.join()).collect(Collectors.toList());
});
finalList- 在此列表中,我希望 fetch 调用返回所有已完成的期货。
在 finalList 中,我总是得到 2 个对象,但 fetchData 运行了 5 次(基于实例数),在所有剩余的异步调用都完成后,我看到了日志。有人可以在这里帮忙。
观察:- 将主线程置于睡眠状态 30 秒后,我可以看到列表中有所有 5 个对象。有人可以告诉为什么主线程根本没有等待所有期货完成。
解决方案
你有一个竞争条件:
classInstance.fetchData().thenApply(x->{
futureList.add(x);
});
这段代码意味着只有当futurex
完成时,x
才会被添加到futureList
. 这可能在 10 毫秒或 2 小时内,谁知道呢?(如果未来异常失败,它可能永远不会)。
所以,当代码到达
CompletableFuture.allOf(futureList....
没有“保证”thenApply
被调用。futureList
甚至可以是空的。
您可以更正此代码的一种方法是:
Map<String, SomeClass> allBeans =context.getBeansOfType(SomeClass.class);
List<SomeClass> list=
allBeans.values().stream().collect(SomeClass.toList());
for (SomeClass classInstance: list) {
futureList.add(classInstance.fetchData());
}
或者,如果您确实需要在 a 中做某事thenApply
:
for (SomeClass classInstance: list) {
futureList.add(
classInstance.fetchData().thenApply(x -> whatever(x))
);
}
这样,您futureList
不会在异步结果返回时填充(这是未知的,甚至可能会因异常而失败,但永远不会发生),而是在创建异步调用后立即填充,这正是您真正想要的。
推荐阅读
- c# - 使用复杂对象的嵌套 asp 中继器
- android - 给定场景的测试方法的正确名称是什么?
- javascript - 如何将输入值存储到php变量
- cypress - 赛普拉斯:文件选择器对话框只能在用户激活时显示
- java - org.apache.derby.jdbc.ClientDriver;无法连接
- .net - GitLab - 找不到“单声道”主机
- r - 如何加载esquisse包
- java - 在使用 Java 与 NtlmPasswordAuth 建立 smb 连接时,有没有办法在用户中包含“@”?
- rxjs - RxJs Zip 仅从发送的流中获取第一个值
- django - 依赖下拉过滤器上的占位符