CompletableFuture异步任务编排使用

本文详细介绍了Java中CompletableFuture类的各种方法,如runAsync、supplyAsync用于创建异步任务,allOf和anyOf用于等待多个任务完成,join和get获取任务结果,whenComplete、whenCompleteAsync、exceptionally和handle处理任务完成后的操作,以及串行任务的编排方式。通过实例展示了这些方法的使用和效果,帮助理解异步编程中的任务协调和异常处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

runAsync 和 supplyAsync

  • runAsync(runnable):无返回值
  • runAsync(runnable, executor):无返回值,可自定义线程池
  • supplyAsync(runnable):有返回值
  • supplyAsync(runnable, executor):有回值,可自定义线程池

相关代码演示:

    public static void testOne(){
        CompletableFuture<Void> oneFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end1");
        });
        CompletableFuture<String> twoFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start2");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end2");
            return "this is twoFuture";
        });
        CompletableFuture.allOf(oneFuture, twoFuture).join();
        System.out.println(oneFuture.join());
        System.out.println(twoFuture.join());
    }
start1
start2
end1
end2
null
this is twoFuture

解析:oneFuture.join()获取的执行结果为null,因为runAsync是没有返回结果的。

allOf 和 anyOf

  • allOf(future1,future2,future3…):等待所有future任务都完成,才可以做接下来的事。无返回值
  • anyOf(future1,future2,future3…):任意一个任务完成,就可以做接下来的事。返回object

allOf用法示例:

    public static void testTwo(){
        long startTime = System.currentTimeMillis();
        CompletableFuture<Void> oneFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end1");
        });
        CompletableFuture<String> twoFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start2");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end2");
            return "this is twoFuture";
        });
        CompletableFuture<Integer> threeFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start3");
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end3");
            return 100;
        });
        CompletableFuture.allOf(oneFuture, twoFuture, threeFuture).join();
        System.out.println(twoFuture.join() + threeFuture.join());
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
start2
start3
end1
end3
end2
this is twoFuture100
cost:2067ms

解析:allOf后的join起阻塞主线程作用。从结果可以看出,所有future执行完成后,再执行的主线程逻辑。

anyOf用法示例:

    public static void testThree(){
        long startTime = System.currentTimeMillis();
        CompletableFuture<Void> oneFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end1");
        });
        CompletableFuture<String> twoFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start2");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end2");
            return "this is twoFuture";
        });
        CompletableFuture<Integer> threeFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start3");
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end3");
            return 100;
        });
        Object result = CompletableFuture.anyOf(oneFuture, twoFuture, threeFuture).join();
        System.out.println("result:" + result);
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
start2
start3
end1
result:null
cost:1058ms

解析:oneFuture 最先完成,因为没有返回值,所以获得的结果是null

join 和 get

都是用于获取Completable的返回值的

  • join方法可能会抛出未检验的异常
  • get方法强制用户手动处理异常

whenComplete 和 whenCompleteAsync 和 exceptionally

  • whenComplete:执行当前线程的任务继续执行whenComplete的任务
  • whenCompleteAsync:whenCompleteAsync的任务是由线程池来执行
  • CompleableFuture即使发生异常也会执行whenComplete、whenCompleteAsync
  • exceptionally是用来处理异常的

以whenComplete举例
正常逻辑:

    public static void testFour() {
        long startTime = System.currentTimeMillis();
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end1");
            return 100;
        }).whenComplete((res, e) ->{
            System.out.println("res:" + res);
            System.out.println("e:" + e);
        }).exceptionally((e) ->{
            System.out.println("error:" + e);
            return -1;
        });
        System.out.println("result:" + oneFuture.join());
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
end1
res:100
e:null
result:100
cost:1084ms

捕获和处理异常:

    public static void testFive() {
        long startTime = System.currentTimeMillis();
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end1");
            return 100/0;
        }).whenComplete((res, e) ->{
            System.out.println("res:" + res);
            System.out.println("e:" + e);
        }).exceptionally((e) ->{
            System.out.println("error:" + e);
            return -1;
        });
        System.out.println("result:" + oneFuture.join());
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
end1
res:null
e:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
error:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
result:-1
cost:1073ms

handle 和 handleAsync

  • handle和handleAsync的区别是后者用线程池管理
  • handle相当于whenComplete和exceptionally的组合,能够对异常捕获和处理

handle捕获和处理异常:

    public static void testSix() {
        long startTime = System.currentTimeMillis();
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end1");
            return 100/0;
        }).handle((res, e) ->{
            System.out.println("res:" + res);
            System.out.println("e:" + e);
            return -1;
        });
        System.out.println("result:" + oneFuture.join());
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
end1
res:null
e:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
result:-1
cost:1081ms

串行编排

  • 该模块用到的api都有普通版和async版本,这里不做赘述。async版本可以传入线程池,用线程池管理逻辑。

runAsync().thenRunAsync()

  • runAsync没有返回值,thenRunAsync也没有返回值
    public static void testSeven(){
        long startTime = System.currentTimeMillis();
        CompletableFuture<Void> oneFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
        }).thenRunAsync(() ->{
            System.out.println("do something");
        });
        oneFuture.join();
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
end1
do something
cost:72ms

supplyAsync().thenAcceptAsync((res) ->{})

  • thenAcceptAsync取supplyAsync的返回值,自身没有返回值
    public static void testEight(){
        long startTime = System.currentTimeMillis();
        CompletableFuture<Void> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        }).thenAcceptAsync((res) ->{
            System.out.println("res:"+ res);
        });
        oneFuture.join();
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
end1
res:100
cost:83ms

supplyAsync().thenApplyAsync((res) ->{return}

  • thenApplyAsync取supplyAsync的返回值,自身也有返回值
    public static void testNine(){
        long startTime = System.currentTimeMillis();
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        }).thenApplyAsync((res) ->{
            return 100* 10;
        });
        System.out.println("result:" + oneFuture.join());
        System.out.println("cost:" + (System.currentTimeMillis() - startTime) + "ms");
    }
start1
end1
result:1000
cost:75ms

两个任务都完成,再做其他事

runAfterBothAsync

  • 无入参、无出参
    public static void testTen(){
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        });
        CompletableFuture<Void> twoFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start2");
            System.out.println("end2");
        });
        oneFuture.runAfterBothAsync(twoFuture, ()->{
            System.out.println("do something");
        });
        System.out.println("result:" + oneFuture.join());
    }
start1
end1
start2
end2
do something
result:100

thenAcceptBothAsync

  • 有入参、无出参
    public static void testEleven(){
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        });
        CompletableFuture<Void> twoFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start2");
            System.out.println("end2");
        });
        oneFuture.thenAcceptBothAsync(twoFuture, (res1, res2)->{
            System.out.println("res1:" + res1);
            System.out.println("res2:" + res2);
        });
        System.out.println("result:" + oneFuture.join());
    }
start1
end1
start2
end2
result:100
res1:100
res2:null

thenCombine

  • 有入参、有出参
    public static void testTwelve(){
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        });
        CompletableFuture<Void> twoFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start2");
            System.out.println("end2");
        });
        CompletableFuture<Integer> combineFuture = oneFuture.thenCombine(twoFuture, (res1, res2) -> {
            System.out.println("res1:" + res1);
            System.out.println("res2:" + res2);
            return res1 == 100 ? res1 : -1;
        });
        System.out.println("result1:" + oneFuture.join());
        System.out.println("combine:" + combineFuture.join());
    }
start1
end1
start2
end2
res1:100
res2:null
result1:100
combine:100

任意一个任务完成,再做其他事

runAfterEitherAsync

  • 无入参、无出参
    public static void testThirteen(){
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        });
        CompletableFuture<Void> twoFuture = CompletableFuture.runAsync(() -> {
            System.out.println("start2");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end2");
        });
        oneFuture.runAfterEitherAsync(twoFuture, ()->{
            System.out.println("do something");
        });
        System.out.println("result:" + oneFuture.join());
    }
start1
end1
start2
result:100
do something

acceptEitherAsync

  • 有入参、无出参
    public static void testFourteen(){
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        });
        CompletableFuture<Integer> twoFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start2");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end2");
            return 10;
        });
        oneFuture.acceptEitherAsync(twoFuture, (res)->{
            System.out.println("res:"+ res);
        });
        System.out.println("result:" + oneFuture.join());
    }
start1
end1
start2
result:100
res:100

applyToEitherAsync

  • 有入参、有出参
    public static void testFifteen(){
        CompletableFuture<Integer> oneFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start1");
            System.out.println("end1");
            return 100;
        });
        CompletableFuture<Integer> twoFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("start2");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end2");
            return 10;
        });
        CompletableFuture<Integer> applyFuture = oneFuture.applyToEitherAsync(twoFuture, (res) -> {
            System.out.println("res:" + res);
            return res * 10;
        });
        System.out.println("result:" + oneFuture.join());
        System.out.println("applyFuture:" + applyFuture.join());
    }
start1
end1
start2
result:100
res:100
applyFuture:1000

总结

根据以上api,在多任务的情况下可以实现任意组合,实现异步执行逻辑,并提高了代码的执行效率。

### 使用 `CompletableFuture` 进行异步操作的编排 #### 什么是 `CompletableFuture` `CompletableFuture` 是 Java 8 中引入的一个强大工具,用于简化异步编程的复杂性[^1]。它不仅继承了 `Future` 接口的功能,还增加了许多新的特性,比如支持函数式编程风格、链式调用以及多种组合方法。 #### 创建和使用 `CompletableFuture` 以下是几个常见的场景及其对应的代码示例: --- ##### 场景一:简单的异步任务 如果有一个独立的任务需要异步执行,则可以直接使用 `runAsync()` 或者 `supplyAsync()` 方法来启动该任务。 ```java // 异步运行无返回值的任务 CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { System.out.println("Running async task..."); }); future.join(); // 等待任务完成 ``` 对于有返回值的情况,可以使用 `supplyAsync()`: ```java // 异步运行并返回结果的任务 CompletableFuture<String> resultFuture = CompletableFuture.supplyAsync(() -> { return "Hello from supplyAsync"; }); String result = resultFuture.join(); System.out.println(result); ``` --- ##### 场景二:任务链式调用 当一个任务的结果作为另一个任务的输入时,可以使用 `.thenApply()` 来构建任务链条。 ```java CompletableFuture<Integer> chainResult = CompletableFuture.supplyAsync(() -> { return 42; }).thenApply(number -> number * 2); int finalResult = chainResult.join(); System.out.println(finalResult); // 输出 84 ``` 还可以进一步扩展此链条,例如加入日志记录或其他逻辑: ```java CompletableFuture<Integer> extendedChain = CompletableFuture.supplyAsync(() -> { return 42; }) .thenApply(number -> number * 2) .thenApply(number -> number + 10) // 添加额外的操作 .handle((result, exception) -> { // 处理异常或正常结果 if (exception != null) { return -1; // 返回默认值 } return result; }); System.out.println(extendedChain.join()); // 输出最终结果 ``` --- ##### 场景三:并发任务组合 有时我们需要等待多个异步任务全部完成后再继续下一步工作,这时可以用 `allOf()`;而如果我们只关心第一个完成的任务,则可以选择 `anyOf()`。 ###### 使用 `allOf()` 假设存在两个耗时较长的任务 A 和 B,只有它们都完成后才能得到最终结果: ```java CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) {} return "Task A Result"; }); CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) {} return "Task B Result"; }); // 组合两个任务 CompletableFuture<Void> combinedTasks = CompletableFuture.allOf(taskA, taskB); combinedTasks.join(); System.out.println("All tasks completed."); System.out.println("Task A: " + taskA.join()); System.out.println("Task B: " + taskB.join()); ``` ###### 使用 `anyOf()` 假如只需其中一个任务先完成即可提前结束流程: ```java CompletableFuture<?> firstCompleted = CompletableFuture.anyOf( CompletableFuture.supplyAsync(() -> { try { Thread.sleep(500); } catch (InterruptedException e) {} return "Fast Task"; }), CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) {} return "Slow Task"; }) ); System.out.println(firstCompleted.join()); // 打印较快的那个任务结果 ``` --- ##### 场景四:错误处理 在实际开发过程中不可避免会遇到各种异常情况,因此合理地捕获和处理这些异常非常重要。可以通过 `.handle()` 或 `.exceptionally()` 实现这一点。 ```java CompletableFuture<String> errorHandlingExample = CompletableFuture.supplyAsync(() -> { throw new RuntimeException("Something went wrong!"); }).exceptionally(ex -> { return "Default Value"; // 当发生异常时返回备用数据 }); System.out.println(errorHandlingExample.join()); // 输出 Default Value ``` 或者更复杂的例子结合 `.whenComplete()` 提供更多上下文信息: ```java CompletableFuture<String> complexErrorHandling = CompletableFuture.supplyAsync(() -> { throw new IllegalArgumentException("Invalid input"); }).whenComplete((value, throwable) -> { if (throwable != null) { System.err.println("Exception occurred: " + throwable.getMessage()); } else { System.out.println("Value computed successfully: " + value); } }); complexErrorHandling.join(); ``` --- #### 总结 通过上述案例可以看出,`CompletableFuture` 不仅能帮助开发者轻松管理单个异步任务,还能高效协调多任务之间的关系,并且具备完善的错误恢复机制[^3]。相比传统的 `Future` API 更加灵活便捷[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值