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

输出结果:

相关推荐
麻瓜生活睁不开眼2 小时前
Android16修改全局桌面视图边框四直角显示为弧边圆角
android·java·深度学习
dear_bi_MyOnly2 小时前
【MyBatis 操作数据库】
java·数据库·学习·mybatis·学习方法
Wang's Blog3 小时前
Go-Zero 项目开发43:基于 Filebeat 收集各个服务的日志信息
开发语言·golang·go-zero·filebeat
2601_953720823 小时前
【计算机毕业设计】基于Spring Boot的心理健康咨询与评测系统的设计与实现
java·spring boot·后端
丈剑走天涯4 小时前
JDK 17 正式特性
java·开发语言
秋田君4 小时前
QT_QFontDialog类字体对话框
开发语言·qt
圣光SG4 小时前
Java操作题练习(七)
java·开发语言·算法
麻瓜老宋5 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十三步,多行输入、进制输出、错误恢复、常量折叠、配置加载等
c语言·开发语言·atomcode
AFinalStone5 小时前
Android 7系统休眠唤醒(六)唤醒全链路
android·电源管理·休眠唤醒
q567315235 小时前
企业级 HTTP 代理采购选型:技术评估清单 15 项
开发语言·网络·爬虫·网络协议·http·隧道ip·代理ip