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");
    }
}

输出结果:

相关推荐
余额瞒着我当琳3 分钟前
C++--vector第二讲:手写 C++ STL:vector 源码剖析与迭代器失效分析
android·java·c++
xixiaoyunya4 分钟前
从零搭建跨域互联网络:个人与小团队的轻量组网方案技术解析
开发语言·智能路由器·php
程序员-珍7 分钟前
安卓开发:同名 styles.xml 在不同分支/文件夹的合并规则
android·xml·前端
资源大佬星 课it9 分钟前
黑马 Java+AI新版V16零基础就业班视频课程百度网盘下载
java·开发语言·人工智能
zmzb010310 分钟前
Python课后习题训练记录Day193
开发语言·python
郝学胜-神的一滴15 分钟前
[简化版 GAMES 104] 现代游戏引擎 06:从Tick时序到邮局模型,拆解确定性世界的底层密码
开发语言·c++·游戏引擎·图形渲染·软件开发·opengl
二十雨辰15 分钟前
[Java]-微服务面试题
java·开发语言·微服务
不会代码的小猴16 分钟前
6. Qt网络编程
开发语言·c++·笔记·qt·算法
我命由我1234517 分钟前
Compose Codelab 学习 - Compose 中的基本布局
android·java·java-ee·kotlin·android studio·android-studio·android runtime
ii_best18 分钟前
手机自动化脚本按键精灵实战:随机布局安全数字键盘的自动化输入方案
android·运维·ios·自动化·手机