Java8中CompletableFuture.allOf的使用

目录标题

CompletableFuture.allOf(...);

CompletableFuture.allOf(...) 本身不会等待所有的 CompletableFuture 完成,它只是返回一个新的 CompletableFuture,这个新未来对象会在所有给定的未来对象完成时完成。

默认情况下,allOf 会等待所有的任务都完成,即使其中有一个失败了,也不会影响其他任务继续执行。

java 复制代码
public class CompletableFutureExample {
    public static void main(String[] args) {
        // 创建一个任务列表
        List<CompletableFuture<String>> futureList = new ArrayList<>();

        long startTime = System.currentTimeMillis();
        // 添加一些异步任务
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    //睡眠一秒
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (taskId == 2) {
                    throw new RuntimeException("task=" + taskId + ",执行异常");
                }
                return "Result of Task " + taskId;
            });
            futureList.add(future);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("[startTime,endTime1]=" + (endTime1 - startTime) + "ms");

        // 使用 allOf 方法来等待所有任务完成
        CompletableFuture<Void> allFutures =
                CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));

        long endTime2 = System.currentTimeMillis();
        System.out.println("[startTime,endTime2]=" + (endTime2 - startTime) + "ms");
        

        long endTime3 = System.currentTimeMillis();
        System.out.println("[startTime,endTime3]=" + (endTime3 - startTime) + "ms");

        // 打印每个任务的结果
        for (CompletableFuture<String> future : futureList) {
            try {
                // 注意:如果某个任务失败,这里会抛出异常
                String result = future.get();
                System.out.println(result);
            } catch (Exception e) {
                System.err.println("Task failed with exception: " + e.getCause());
            }
        }

        long endTime4 = System.currentTimeMillis();
        System.out.println("[startTime,endTime4]=" + (endTime4 - startTime) + "ms");
    }
}

执行结果:

CompletableFuture.allOf(...).get();

该代码在调用 get() 时会阻塞当前线程,直到所有的 CompletableFuture 完成。如果其中一个或多个任务失败,它会抛出 ExecutionException,需要捕获并处理异常。

java 复制代码
public class CompletableFutureExample {
    public static void main(String[] args) {
        // 创建一个任务列表
        List<CompletableFuture<String>> futureList = new ArrayList<>();

        long startTime = System.currentTimeMillis();
        // 添加一些异步任务
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    //睡眠一秒
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (taskId == 2) {
                    throw new RuntimeException("task=" + taskId + ",执行异常");
                }
                return "Result of Task " + taskId;
            });
            futureList.add(future);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("[startTime,endTime1]=" + (endTime1 - startTime) + "ms");

        // 使用 allOf 方法来等待所有任务完成
        CompletableFuture<Void> allFutures =
                CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));

        long endTime2 = System.currentTimeMillis();
        System.out.println("[startTime,endTime2]=" + (endTime2 - startTime) + "ms");

        try {
            allFutures.get();
        } catch (InterruptedException | ExecutionException e) {
            System.err.println("An error occurred: " + e.getMessage());
        }

        long endTime3 = System.currentTimeMillis();
        System.out.println("[startTime,endTime3]=" + (endTime3 - startTime) + "ms");

        // 打印每个任务的结果
        for (CompletableFuture<String> future : futureList) {
            try {
                // 注意:如果某个任务失败,这里会抛出异常
                String result = future.get();
                System.out.println(result);
            } catch (Exception e) {
                System.err.println("Task failed with exception: " + e.getCause());
            }
        }

        long endTime4 = System.currentTimeMillis();
        System.out.println("[startTime,endTime4]=" + (endTime4 - startTime) + "ms");
    }
}

执行结果:

CompletableFuture.allOf(...).join();

该代码同样会阻塞当前线程,直到所有的 CompletableFuture 完成。不同于 get(),join() 方法在任务失败时会抛出一个未检查的异常(CompletionException),而不需要处理检查型异常。

java 复制代码
public class CompletableFutureExample {
    public static void main(String[] args) {
        // 创建一个任务列表
        List<CompletableFuture<String>> futureList = new ArrayList<>();

        long startTime = System.currentTimeMillis();
        // 添加一些异步任务
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    //睡眠一秒
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (taskId == 2) {
                    throw new RuntimeException("task=" + taskId + ",执行异常");
                }
                return "Result of Task " + taskId;
            });
            futureList.add(future);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("[startTime,endTime1]=" + (endTime1 - startTime) + "ms");

        // 使用 allOf 方法来等待所有任务完成
        CompletableFuture<Void> allFutures =
                CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));

        long endTime2 = System.currentTimeMillis();
        System.out.println("[startTime,endTime2]=" + (endTime2 - startTime) + "ms");

        allFutures.join();

        long endTime3 = System.currentTimeMillis();
        System.out.println("[startTime,endTime3]=" + (endTime3 - startTime) + "ms");

        // 打印每个任务的结果
        for (CompletableFuture<String> future : futureList) {
            try {
                // 注意:如果某个任务失败,这里会抛出异常
                String result = future.get();
                System.out.println(result);
            } catch (Exception e) {
                System.err.println("Task failed with exception: " + e.getCause());
            }
        }

        long endTime4 = System.currentTimeMillis();
        System.out.println("[startTime,endTime4]=" + (endTime4 - startTime) + "ms");
    }
}

执行结果:

不用强制捕获异常,但是如果有异常会直接抛出!

java 复制代码
allFutures.join();

换成

java 复制代码
try {
   allFutures.join();
} catch (Exception e) {
   System.err.println("An error occurred: " + e.getMessage());
}

执行结果:

总结

仅仅调用 CompletableFuture.allOf(...) 不会导致等待,它只构造一个新的 CompletableFuture。只有调用 get() 或 join() 才会真正等待所有线程执行完毕。get() 需要处理检查型异常,而 join() 则更简洁,不需要处理检查型异常,适合于不需要具体处理的场景。

如何优雅的处理异常呢?

如果异常的情况不需要处理,比如给默认值这种情况,那么下面的写法优雅一些。

java 复制代码
public class CompletableFutureExample {
    public static void main(String[] args) {
        // 创建一个任务列表
        List<CompletableFuture<String>> futureList = new ArrayList<>();

        long startTime = System.currentTimeMillis();
        // 添加一些异步任务
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    //睡眠一秒
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (taskId == 2) {
                    throw new RuntimeException("task=" + taskId + ",执行异常");
                }
                return "Result of Task " + taskId;
            }).handle((result, ex) -> {
                if (ex != null) {
                    // 处理异常并返回 null
                    System.err.println("Task failed: " + ex.getCause());
                    return null;  // 返回 null 表示任务失败
                }
                return result;  // 返回结果
            });
            futureList.add(future);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("[startTime,endTime1]=" + (endTime1 - startTime) + "ms");

        // 使用 allOf 方法来等待所有任务完成
        CompletableFuture<Void> allFutures =
                CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));

        // 处理结果和异常
        CompletableFuture<List<String>> resultsFuture = allFutures.thenApply(v ->
                futureList.stream()
                        .map(CompletableFuture::join)  // 使用 join() 获取结果
                        .filter(result -> result != null)  // 过滤掉失败的结果
                        .collect(Collectors.toList())  // 收集成功的结果
        );

        long endTime2 = System.currentTimeMillis();
        System.out.println("[startTime,endTime2]=" + (endTime2 - startTime) + "ms");

        // 打印每个任务的结果
        List<String> futureResultList = resultsFuture.join();

        long endTime3 = System.currentTimeMillis();
        System.out.println("[startTime,endTime3]=" + (endTime3 - startTime) + "ms");


        for (String result : futureResultList) {
            System.out.println(result);
        }

        long endTime4 = System.currentTimeMillis();
        System.out.println("[startTime,endTime4]=" + (endTime4 - startTime) + "ms");
    }
}

输出结果:

相关推荐
魔都吴所谓4 分钟前
【Python】 多线程 & 多进程&协程 常见题 + 应用场景整理
开发语言·python
Irene199113 分钟前
Flink 学习日志 01:前端转大数据的实战避坑指南
java·jvm·flink
Thomas.Sir14 分钟前
第1课:SpringBoot 4.x 快速上手:新特性、环境准备与第一个HelloWorld程序
java·spring boot
king135987455017 分钟前
LiteRT Tensor API:C++ 编写端侧模型图,XNNPACK、GPU 与 NPU 怎么选?
开发语言·c++·人工智能·chatgpt·架构·aigc
geovindu18 分钟前
rust: Template Method Pattern(续)
开发语言·后端·设计模式·rust·行为模式·板方法模式
外收内放20 分钟前
面向对象高级(封装)
开发语言·python
小铁-Android25 分钟前
CompletableDeferred:Kotlin 协程中用于一次性挂起通信的工具
android·kotlin
恋猫de小郭28 分钟前
Flutter 的文字为什么比 SwiftUI 更细?问题主要在 Skia 的 256 项查找表里
android·前端·flutter
ii_best32 分钟前
安卓手机开发、iOS 手机开发都能用:按键精灵远程调试,设备在千里外也能改脚本
android·ios·智能手机·自动化·按键精灵
devilnumber34 分钟前
Java 内部迭代 vs 外部迭代:从原理到实战避坑
java·开发语言