CompletableFuture基本使用

本文介绍了Java8的CompletableFuture,它是Future的扩展,用于简化异步编程。内容包括CompletableFuture的概念、创建方式,以及CompletionStage接口的作用。还详细讲解了异步回调的各种方法如thenApply、thenAccept、thenRun和thenCompose的用法,以及聚合操作如allOf、anyOf、thenCombine等。最后,讨论了结果或异常处理的策略,如whenComplete、handle和exceptionally。

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

CompletableFuture是什么

  • CompletableFuture是Java8中提供的Future的扩展功能,简化异步编程的复杂性;
  • 引入函数式编程,通过回调的方式处理计算结果,也提供了转换和组合的方法;
  • 它实现了Future和CompletionStage接口;
  • 借助CompletionStage的方法可以实现链式调用;
  • 一个CompletetableFuture就代表了一个任务,可以用then,when等操作来防止阻塞和轮询isDone的现象出现;
  • 它可能代表一个明确完成的Future,也有可能代表一个完成阶段( CompletionStage ),它支持在计算完成以后触发一些函数或执行某些动作;

创建方式

1、创建一个具有默认结果的 CompletableFuture,不经常使用;

2、supplyAsync表示创建带返回值的异步任务,相当于ExecutorService submit(Callable<T> task),这两方法的效果跟submit是一样的。

3、runAsync表示创建无返回值的异步任务,相当于ExecutorService submit(Runnable task);

样例:

public static void main(String[] args) {
        // runAsync的使用
        CompletableFuture<Void> runFuture = CompletableFuture.runAsync(() -> System.out.println("Hello runAsync!"));

        // supplyAsync的使用
        CompletableFuture<String> supplyFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("Hello supplyAsync!");
            return "Hello World";
        });

        // runAsync的future没有返回值,输出null
        System.out.println("runAsync结果:" + runFuture.join());
        // supplyAsync的future,有返回值
        System.out.println("supplyAsync结果:" + supplyFuture.join());
}

结果:


创建形式:

1、默认的使用公共的 ForkJoinPool 线程池执行(默认线程数是 CPU 的核数);如果机器是单核的,则默认使用ThreadPerTaskExecutor,该类是一个内部类,每次执行execute都会创建一个新线程

2、提供一个主动创建线程池,相比于ForkJoinPool的好处是,可以通过自定义不同场景的线程池,来进行业务划分方便发现问题,还有一个好处就是ForkJoinPool是一种共享线程,发生阻塞会造成其他线程无法获取执行机会。

注:自定义线程池有个队列满了的拒绝策略,如果采用丢弃策略的拒绝策略,并且allOf方法和get方法如果没有设置超时则会无限期的等待下去

样例:

public static void main(String[] args) {
    CompletableFuture.runAsync(() -> System.out.println("默认线程池执行--" + Thread.currentThread().getName()));

    // 可以自定义线程池
    ExecutorService executor = Executors.newCachedThreadPool();
    CompletableFuture.runAsync(() -> System.out.println("自定义线程池执行--" + Thread.currentThread().getName()), executor);
}

结果:


CompletionStage是什么

Java8新增得一个接口,代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段。目前只有CompletableFuture一个实现类

  • 一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())

  • 一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发

异步回调

then前缀:

某个任务执行完成后执行的动作(即回调方法)可以理解为串行化一个任务接着一个执行

Async后缀的区别:fn是否异步执行

thenApply系列:将上一个任务任务的执行结果,交给后面的Function,返回一个具有处理结果的Future对象

thenAccept系列:将上一个任务任务的执行结果(即方法返回值)作为入参传递到回调方法中,无返回值

thenRun系列:无入参无返回值。不关心结果,只对结果执行Action

thenCompose:用来连接两个有依赖关系的任务

thenApply和thenCompose的区别

public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);

public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);

Function<? super T,? extends U> T:上一个任务返回结果的类型  U:当前任务的返回值类型

两个方法的返回值都是CompletionStage<U>,不同之处在于它们的传入参数fn.

  • 对于thenApplyfn函数是一个对一个已完成的stage或者说CompletableFuture的的返回值进行计算、操作;
  • 对于thenComposefn函数是对另一个CompletableFuture进行计算、操作。

样例:

CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> 123).thenApply(num -> "thenApply任务:" + num);
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> 456).thenCompose(num -> CompletableFuture.supplyAsync(() -> "thenCompose任务:" + num));

System.out.println(f1.join());
System.out.println(f2.join());

聚合

1将多个CompletableFuture都执行完成以后,才执行后操作

2、多个CompletableFuture并行执行,相互之间并没有先后依赖顺序。

3多个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null

and

thenCombine系列:两个任务执行完成后,执行下一步操作Function,有入参有返回

thenAcceptBoth系列:两个任务执行完成后,执行下一步操作Consumer,有入参无返回值;

runAfterBoth系列:两个任务都执行完成后,执行下一步操作Runnable,无入参无返回值 

allOf:多个CompletableFuture任务,当所有任务完成时,方法返回CompletableFuture<Void>;

or

applyToEither系列:两个任务任意一个完成,执行下一步操作Function,有入参有返回值CompletableFuture<U>(谁执行的快,就使用那一个结果作为后续任务入参);

acceptEither系列:两个任务任意一个完成,执行下一步操作Function,有入参无返回值CompletableFuture<Void>(谁执行的快,就使用那一个结果作为后续任务入参);

runAfterEither系列:两个任务任意一个完成,执行下一步操作Runnable,无入参无返回值CompletableFuture<Void>

anyOf:多个CompletableFuture任务,只要有一个任务执行完成,方法返回CompletableFuture<Object>;


结果或异常处理

whenComplete

public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);

whenComplete系列:不论上一个阶段是正常/异常完成(即不会对阶段的原来结果产生影响);类似于 try..catch..finanlly 中 finally 代码块,无论是否发生异常都将会执行的。

当某个任务执行完成后,会将执行结果或者执行期间抛出的异常传递给回调方法:

如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,

如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。

handle

public <U> CompletionStage<U> handle (BiFunction<? super T, Throwable, ? extends U> fn);

handle系列:产出型方法,即可以对正常完成的结果进行转换,也可以对异常完成的进行补偿一个结果,即可以改变阶段的现状。跟whenComplete基本一致,区别在于handle的回调方法有返回值,且handle方法返回的CompletableFuture的result是回调方法的执行结果或者回调方法执行期间抛出的异常,与原始CompletableFuture的result无关。

exceptionally

public CompletionStage<T> exceptionally (Function<Throwable, ? extends T> fn);

异常的结果处理(上一个阶段异常完成才会被执行);

使用方式类似于 try catch中的catch代码块中异常处理;当某个任务执行异常时将抛出的异常作为参数传递到回调方法中,如果该任务正常执行,exceptionally方法返回的CompletionStage的result就是该任务正常执行的结果。


 结果获取

CompletableFuture方法执行过程若产生异常,只有get或join方法才能获取到异常

get获取任务返回值,没有则阻塞直到有返回值返回;抛出经过检查的异常InterruptedExceptionExecutionException

getNow:如果结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值;

join获取任务返回值,没有则阻塞直到有返回值返回;抛出未经检查的异常,不会强制抛出,会将异常包装成CompletionException/CancellationException异常;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值