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 分钟前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
十年一梦实验室6 分钟前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
isolusion9 分钟前
Springboot的创建方式
java·spring boot·后端
最爱番茄味15 分钟前
Python实例之函数基础打卡篇
开发语言·python
元争栈道28 分钟前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
zjw_rp37 分钟前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob1 小时前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder1 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
engchina1 小时前
如何在 Python 中忽略烦人的警告?
开发语言·人工智能·python
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎