gpt4 book ai didi

Java并发,什么情况下CompletableFuture.supplyAsync()会返回null

转载 作者:行者123 更新时间:2023-12-03 12:45:10 27 4
gpt4 key购买 nike

在生产环境中发现关于 CompletableFuture.supplyAsync() 的问题我们有如下的批处理方法:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

public class CompletableFutureProblem {
public void batchOperation(){
List<String> stringList = new ArrayList<>();
stringList.add("task1");
stringList.add("task2");
List<CompletableFuture<String>> futures = new ArrayList<>();
stringList.parallelStream().forEach(str -> {
CompletableFuture<String> response = restApiCall(str);
futures.add(response);
});
//futures.add(null);
CompletableFuture<Void> result = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
CompletableFuture<List<String>> convertedResult = result.thenApply(v ->
futures.stream().map(CompletableFuture::join).collect(Collectors.toList())
);
try {
List<String> finishedTask = convertedResult.get();
System.out.println(finishedTask.toString());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}

public CompletableFuture<String> restApiCall(String str){
return CompletableFuture.supplyAsync(() -> {
return "Complete-" + str;
});
}

public static void main(String[] args) {
CompletableFutureProblem problem = new CompletableFutureProblem();
problem.batchOperation();
}
}

当一切正常时会打印:[完成任务2,完成任务1]

但是,有时它会在生产中抛出如下异常:

Exception in thread "main" java.lang.NullPointerException
at java.util.concurrent.CompletableFuture.andTree(CompletableFuture.java:1320)
at java.util.concurrent.CompletableFuture.allOf(CompletableFuture.java:2238)
at third.concurrent.CompletableFutureProblem.batchOperation(CompletableFutureProblem.java:20)
at third.concurrent.CompletableFutureProblem.main(CompletableFutureProblem.java:40)

我调查了 CompletableFuture.allOf() 源代码发现如果列表 futures 包含 null,例如 futures.add(null),会抛出异常,但真不知道restApiCall方法中的CompletableFuture.supplyAsync()在什么情况下会返回null ?

感谢您耐心阅读这篇长文。

最佳答案

futures 正在被多个线程写入,因为您正在使用并行流使用 stringList。但是 futures 是一个 ArrayList,它不是线程安全的。

因此,您无法确定从不同线程添加到其中的每个元素在没有适当同步的情况下是否可见。当您将其转换为数组时,会出现内存可见性问题,这是不确定的,因此有时它会按预期工作。

要解决此问题,通常会使用并发集合。然而,在这种情况下,并行化 CompletableFuture.supplyAsync() 没有意义,因为它是一个非阻塞调用。因此,最好的解决方案是循环遍历列表:

stringList.forEach(str -> {

此外,toArray() 中的预分配数组应该为空:

futures.toArray(new CompletableFuture[0])

关于Java并发,什么情况下CompletableFuture.supplyAsync()会返回null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64940428/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com