我正在对数据库进行多个异步调用。我将所有这些异步调用存储在List<CompletableFuture<X>> list
上。我想收集所有的结果,所以我需要等待所有这些调用完成。
一种方法是创建一个CompletableFuture.allOf(list.toArray(...))...
另一种方法是使用:list.stream.map(cf -> cf.join())...
我只是想知道,与直接等待单个CompletableFuture完成相比,创建全局CompletableFuture并等待它完成(当所有单独的CompletableFuture都完成时)是否有什么好处。
发布于 2021-10-31 07:47:55
无论哪种方式,main
线程都会被阻塞。
static CompletableFuture<Void> getFailingCF() {
return CompletableFuture.runAsync(() -> {
System.out.println("getFailingCF :: Started getFailingCF.. ");
throw new RuntimeException("getFailingCF:: Failed");
});
}
static CompletableFuture<Void> getOkCF() {
return CompletableFuture.runAsync(() -> {
System.out.println("getOkCF :: Started getOkCF.. ");
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
System.out.println("getOkCF :: Completed getOkCF.. ");
});
}
public static void main(String[] args) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
futures.add(getFailingCF());
futures.add(getOkCF());
// using CompletableFuture.allOf
var allOfCF = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
allOfCF.join();
// invoking join on individual CF
futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
在上面的代码片段中,区别在于处理异常:CompletableFuture.allOf(..)
包装任何CompletableFuture
抛出的异常,同时允许其余的线程(执行CompletableFuture
)继续它们的执行。
list.stream.map(cf -> cf.join())...
方式立即抛出异常并终止应用程序(以及列表中执行CFs的所有线程)。
请注意,在join()
上调用allOf
也会引发包装异常。它还将终止该应用程序。但是,到目前为止,与list.stream.map(cf -> cf.join())...
不同的是,剩下的线程已经完成了它们的处理。
allOfCF.whenComplete(..)
是处理所有CFs的执行结果(正常或异常)的优雅方法之一:
allOfCF.whenComplete((v, ex) -> {
System.out.println("In whenComplete...");
System.out.println("----------- Exception Status ------------");
System.out.println(" 1: " + futures.get(0).isCompletedExceptionally());
System.out.println(" 2: " + futures.get(1).isCompletedExceptionally());
});
在list.stream.map(cf -> cf.join())...
方式中,需要用try/catch
包装join()
调用。
https://stackoverflow.com/questions/69767216
复制相似问题