CompletableFuture.allOf() 比 CompletableFuture.join() 的循环在等待完成时有什么优势吗?

Has CompletableFuture.allOf() any advantage over a loop with CompletableFuture.join() when just waiting for completion?

我正在对我的数据库进行多次异步调用。我将所有这些异步调用存储在 List<CompletableFuture<X>> list 上。我想一起收集所有结果,所以我需要等待所有这些调用完成。

一种方法是创建一个 CompletableFuture.allOf(list.toArray(...))...

另一种方法是使用:list.stream.map(cf -> cf.join())...

我只是想知道创建全局 CompletableFuture 并等待它完成(当所有单独的 CompletableFuture 完成时)比直接等待单独的 CompletableFutures 完成是否有任何优势。

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())...方式立即抛出异常并终止应用程序(以及执行列表中CF的所有线程)。

请注意,在 allOf 上调用 join() 也会抛出包装异常。它还将终止该应用程序。但是,此时,与 list.stream.map(cf -> cf.join())... 不同的是,其余线程已完成处理。


allOfCF.whenComplete(..) 是处理所有CF的执行结果(正常或异常)的优雅方式之一:

 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())... 方式中,需要将 join() 调用包装在 try/catch.