我正在尝试转换List<CompletableFuture<X>>
为CompletableFuture<List<T>>
。当您有许多异步任务并且需要获得所有异步任务的结果时,这非常有用。
如果它们中的任何一个失败,那么最终的未来将失败。这就是我实现的方式:
public static <T> CompletableFuture<List<T>> sequence2(List<CompletableFuture<T>> com, ExecutorService exec) {
if(com.isEmpty()){
throw new IllegalArgumentException();
}
Stream<? extends CompletableFuture<T>> stream = com.stream();
CompletableFuture<List<T>> init = CompletableFuture.completedFuture(new ArrayList<T>());
return stream.reduce(init, (ls, fut) -> ls.thenComposeAsync(x -> fut.thenApplyAsync(y -> {
x.add(y);
return x;
},exec),exec), (a, b) -> a.thenCombineAsync(b,(ls1,ls2)-> {
ls1.addAll(ls2);
return ls1;
},exec));
}
要运行它:
ExecutorService executorService = Executors.newCachedThreadPool();
Stream<CompletableFuture<Integer>> que = IntStream.range(0,100000).boxed().map(x -> CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
return x;
}, executorService));
CompletableFuture<List<Integer>> sequence = sequence2(que.collect(Collectors.toList()), executorService);
如果其中任何一个失败,则失败。即使有一百万个期货,它也能提供预期的输出。我的问题是:假设如果有超过5000个期货,并且其中任何一个失败,我都会得到StackOverflowError
:
java.util.concurrent.CompletableFuture.internalComplete(CompletableFuture.java:210)处的线程“ pool-1-thread-2611”中的java.lang.StackOverflowError,java.util.concurrent.CompletableFuture $ ThenCompose.run(CompletableFuture.java) :1487),位于java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:193),位于java.util.concurrent.CompletableFuture.internalComplete(CompletableFuture.java:210),位于java.util.concurrent.CompletableFuture $ ThenCompose.run( CompletableFuture.java:1487)
我做错了什么?
注意:当任何将来失败时,上述返回的将来都会失败。接受的答案也应考虑这一点。
Collector