提示: 嫌麻烦可以直接跳到"问题"开始看
测试代码
@SpringBootTest
class SpringbootdemoApplicationTests {
@Test
void contextLoads() throws InterruptedException {
RestClient client = new RestClient("http://121.36.151.190:9090");
client.login("admin@abcd.com", "admin");
Map<String, Object> rpcDto = new LinkedHashMap<>();
rpcDto.put("method", "30");
List<Map<String, String>> params = new ArrayList<>();
Map<String, String> param = new LinkedHashMap<>();
param.put("deviceNumber", "12");
params.add(param);
rpcDto.put("params", params);
Map<String, Boolean> res = new LinkedHashMap<>();
List<CompletableFuture<Map<String, Integer>>> futures = new ArrayList<>();
for (int i=0;i<1;i++){
CompletableFuture<Map<String, Integer>> future = CompletableFuture.supplyAsync(
() -> client.getRestTemplate()
.exchange(
"http://xxx.xxx.xxx.xxx:9090" + "/xxxUrl",
HttpMethod.POST,
new HttpEntity<>(rpcDto),
new ParameterizedTypeReference<Map<String, Integer>>() {}
)
.getBody()
);
future.thenAccept(results -> results.keySet().forEach(resultkey -> {
System.out.println("future accepted, setting res as true");
res.put(resultkey, results.get(resultkey)==0);
}));
futures.add(future);
}
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
combinedFutures.thenAccept(r ->
System.out.println("combinedFuture accepted")
);
combinedFutures.whenComplete((v,th) -> {
System.out.println("all completed");
System.out.println(v);
}).join();
System.out.println(res);
System.out.println("watting...");
Thread.sleep(10);
System.out.println(res);
}
}
执行结果
combinedFuture accepted
all completed
null
{}
watting…
future accepted, setting res as true
{12=true}
总结
主线程创建一批子线程, 子线程开始执行远程调用
主线程走到join方法时开始等待
最后一个子线程的远程调用完成, 拿到things board的返回值
接下来至少有两个线程都在执行: 主线程 和 最后一个子线程
主线程继续执行join()及其后面的代码;
子线程执行远程调用完成之后的回调代码(即将结果put进res)
问题
主线程在从map里取结果时会取到null值, 因为可能子线程还没来得及将result赋值进去
解决
将赋值代码从thenAccept挪到外面. 变动的代码如下
List<CompletableFuture<Map<String, Integer>>> futures = new ArrayList<>();
for (int i=0;i<1;i++){
CompletableFuture<Map<String, Integer>> future = CompletableFuture.supplyAsync(
() -> client.getRestTemplate()
.exchange(
"http://xxx.xxx.xx.xxx:9090" + "/xxxUrl",
HttpMethod.POST,
new HttpEntity<>(rpcDto),
new ParameterizedTypeReference<Map<String, Integer>>() {}
)
.getBody()
);
futures.add(future);
}
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
combinedFutures.thenAccept(r ->
System.out.println("combinedFuture accepted")
);
combinedFutures.whenComplete((v,th) -> {
System.out.println("all completed");
}).join();
for (CompletableFuture<Map<String, Integer>> future : futures){
Map<String, Integer> result = future.join();
result.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
res.put(s, integer==0);
}
});
}
结果
combinedFuture accepted
all completed
{12=true}
watting...
{12=true}
本文通过测试代码展示了在使用CompletableFuture.allOf时,主线程可能会因子线程未及时完成而获取到null结果的问题。文章讨论了问题的原因,并提供了将赋值操作移出thenAccept之外的解决方案,以确保主线程能正确获取所有子任务的结果。
1万+

被折叠的 条评论
为什么被折叠?



