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

输出结果:

相关推荐
XDH_CS20 小时前
MySQL 8.0 安装与 MySQL Workbench 使用全流程(超详细教程)
开发语言·数据库·mysql
木易 士心20 小时前
别再只会用 drawCircle 了!一文搞懂 Android Canvas 底层机制
android
小短腿的代码世界20 小时前
Qt实时盈亏计算深度解析:从持仓数据到动态盈亏展示
开发语言·qt
小康小小涵20 小时前
基于ESP32S3实现无人机RID模块底层源码编译
linux·开发语言·python
lzjava202420 小时前
Python的函数
开发语言·python
掌心向暖RPA自动化21 小时前
如何获取网页某个元素在屏幕可见部分的中心坐标影刀RPA懒加载坐标定位技巧
java·javascript·自动化·rpa·影刀rpa
AtOR CUES21 小时前
MySQL——表操作及查询
android·mysql·adb
Awesome Baron21 小时前
skill、tool calling、MCP区别
开发语言·人工智能·python
日取其半万世不竭21 小时前
Minecraft Java版社区服务器搭建教程(Linux,适合新手)
java·linux·服务器
Python私教21 小时前
GenericAgent PySide6 桌面应用深度解析:悬浮按钮 + 聊天面板的原生 Qt 方案
开发语言·数据库·qt