> 文档中心 > CompletableFuture用法详解

CompletableFuture用法详解


CompletableFuture用法详解

前言

JDK汇总已经提供了异步编程的类Future,为什么还要CompletableFuture这个类呢?

我们通常在使用Future接口异步编程时,获取结果都需要阻塞获取。主线程中会阻塞,其实最好的结果是让它执行完结果后通知我们获取。

还有一种情况,当我们需要多个异步结果嵌套时候,Future这个接口就就不能满足我们的实用场景了,可能需要我们手动在里面进行嵌套。

对此,从JDK 8开始,在Concurrent包中提供了一个强大的异步编程工具 CompletableFuture。在JDK8之前,异步编程可以通过线程池和Future来实现。

CompletableFuture

CompletableFuture接口实现了Future 接口,对其功能进行了扩展,使得其功能更加强大,可以事件通知,嵌套等操作。
CompletableFuture用法详解
CompletionStage接口提供了一些方法

    public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);     public CompletionStage<Void> thenAccept(Consumer<? super T> action);      public CompletionStage<Void> thenRun(Runnable action);public CompletionStage<Void> thenRunAsync(Runnable action,    Executor executor);    public <U,V> CompletionStage<V> thenCombineAsync (CompletionStage<? extends U> other,  BiFunction<? super T,? super U,? extends V> fn);      public <U> CompletableFuture<Void> thenAcceptBoth( CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) { return biAcceptStage(null, other, action);    }    public CompletableFuture<T> whenComplete( BiConsumer<? super T, ? super Throwable> action) { return uniWhenCompleteStage(null, action);    }

等等这里列举了一部分接口

这里介绍几个最常用的接口

runAsync 与 supplyAsync

可以指定线程池,默认是
在这里插入图片描述
构造
在这里插入图片描述

有时候我们异步执行完结果后,可以额外通知做一些事情。

whenComplete 表示执行完后通知事件

//第一个参数是返回值,第二个是执行的异常    public CompletableFuture<T> whenComplete( BiConsumer<? super T, ? super Throwable> action) { return uniWhenCompleteStage(null, action);    }    //异步通知事件    public CompletableFuture<T> whenCompleteAsync( BiConsumer<? super T, ? super Throwable> action) { return uniWhenCompleteStage(asyncPool, action);    }    //带线程池的通知    public CompletableFuture<T> whenCompleteAsync( BiConsumer<? super T, ? super Throwable> action, Executor executor) { return uniWhenCompleteStage(screenExecutor(executor), action);    }

例如

 Executor executor  = Executors.newFixedThreadPool(10); CompletableFuture.runAsync(()->{     try {  TimeUnit.SECONDS.sleep(2);     } catch (InterruptedException e) {  e.printStackTrace();     }     System.out.println(" =========== do  some ting  ========== ");     },executor).whenComplete((v,throwable)->{     //throwable 是执行中返回异常     System.out.println(" 执行结束 通知 .... " + v ); });

执行如下
CompletableFuture用法详解

  • supplyAsync 有返回值
   CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {     try {  TimeUnit.SECONDS.sleep(2);     } catch (InterruptedException e) {  e.printStackTrace();     }     System.out.println(" =========== do  some ting  ========== ");     return "supplyAsync str "; }, executor).whenComplete((v, throwable) -> {     //throwable 是执行中返回异常     System.out.println(" 执行结束 通知 .... " + v); });

执行结果
在这里插入图片描述

thenRun、thenAccept和thenApply

有时候异步执行完任务会,再做一些事情,也可能根据返回值做一些操作。
此时可以用到这几个事件。

对于 Future,在提交任务之后,只能调用 get()等结果返回;但对于 CompletableFuture,可以在
结果上面再加一个callback,当得到结果之后,再接着执行callback。

thenRun
   Executor executor = Executors.newFixedThreadPool(10); CompletableFuture.runAsync(() -> {     try {  TimeUnit.SECONDS.sleep(2);     } catch (InterruptedException e) {  e.printStackTrace();     }     System.out.println(" =========== do  some ting  ========== "); }, executor).thenRun(() -> {     try {  TimeUnit.SECONDS.sleep(1);     } catch (InterruptedException e) {  e.printStackTrace();     }     System.out.println("thenRun :  任务执行结束之后执行的语句"); }).whenComplete((v, throwable) -> {     //throwable 是执行中返回异常     System.out.println(" 执行结束 通知 .... " + v); });
thenAccept

这里用的无返回值, 会是Null, 返回值可以用 supplyAsync方法

      CompletableFuture.runAsync(() -> {     try {  TimeUnit.SECONDS.sleep(2);     } catch (InterruptedException e) {  e.printStackTrace();     }     System.out.println(" =========== do  some ting  ========== "); }, executor).thenAccept(new Consumer<Void>() {     @Override     public void accept(Void unused) {  // 由于是 Void 无返回值 则是null ,使用 有返回值结果的 supplyAsync 会拿到值  System.out.println(" thenAccept : 执行任务完后获取前面执行的结果  =  " + unused);     } }).whenComplete((v, throwable) -> {     //throwable 是执行中返回异常     System.out.println(" 执行结束 通知 .... " + v); });
thenApply

thenApply 可以链式计算,执行结束可以接着thenApply操作。

CompletableFuture.supplyAsync(() -> {     try {  TimeUnit.SECONDS.sleep(2);     } catch (InterruptedException e) {  e.printStackTrace();     }     System.out.println(" =========== do  some ting  ========== ");     return " supplyAsync : thenApply(function)"; }, executor).thenApply(new Function<String, Object>() {     @Override     public String apply(String unused) {  System.out.println( " 接收上面返回值 接着计算 unused :" + unused);  return unused + " :apply :  " + 1234567;     } }).whenComplete((result, throwable) -> {     //throwable 是执行中返回异常     // result 最终返回值     System.out.println(" 执行结束 通知 .... " + result); });

thenCompose 与 thenCombine

thenApply接收的是一个Function,但是这个Function的返回值是一个通常的基
本数据类型或一个对象,而不是另外一个 CompletableFuture。如果 Function 的返回值也是一个
CompletableFuture,就会出现嵌套的CompletableFuture。

没有 thenCompose 时候嵌套 任务,用 thenApply来实现
thenApply中有个函数接口,一个是T入参(也就是任务结果) 一个是返回值(最后嵌套里的返回值)。
在这里插入图片描述
会继续返回我们的 CompletableFuture
在这里插入图片描述

  CompletableFuture<CompletableFuture<Integer>> completableFutureCompletableFuture = CompletableFuture.supplyAsync(() -> {     System.out.println(" =========== do  some ting  ========== ");     return "   没有 thenCompose 时候嵌套 任务 "; }, executor).thenApply(new Function<String, CompletableFuture<Integer>>() {     @Override     public CompletableFuture<Integer> apply(String s) {  return CompletableFuture.supplyAsync(() -> {      return s.length();  });     } }).whenComplete((result, throwable) -> {     System.out.println(" 最后通知返回," + result);     System.out.println(" 最后通知返回异常 ," + throwable); }); CompletableFuture<Integer> integerCompletableFuture = completableFutureCompletableFuture.get(); //嵌套返回 System.out.println("嵌套返回: " + integerCompletableFuture.get());

可以看到结果,需要获取2次
在这里插入图片描述

thenCombine

可以通过 thenCombine 简化上面的嵌套任务,返回值是一个非嵌套的CompletableFuture

     CompletableFuture<Integer> integerCompletableFuture1 = CompletableFuture.supplyAsync(() -> {     System.out.println(" =========== do  some ting  ========== ");     return " thenCombine(简化嵌套任务)  ";     // 嵌套的CompletableFuture }, executor).thenCompose(new Function<String, CompletionStage<Integer>>() {     @Override     public CompletionStage<Integer> apply(String s) {  System.out.println(" thenCombine(简化嵌套任务)  获取上一步值: " + s);  //嵌套的CompletableFuture 执行任务 返回  return CompletableFuture.supplyAsync(() ->   s.length()  );     } }).whenComplete((result, throwable) -> {     System.out.println(" 最后通知返回," + result);     System.out.println(" 最后通知返回异常 ," + throwable); }); System.out.println(" get : " + integerCompletableFuture1.get());

这里结果我们只需要get一次
在这里插入图片描述

thenCompose

thenCompose

第1个参数是一个CompletableFuture类型,第2个参数是一个方法,并且是一个BiFunction,也就
是该方法有2个输入参数,1个返回值。
从该接口的定义可以大致推测,它是要在2个 CompletableFuture 完成之后,把2个
CompletableFuture的返回值传进去,再额外做一些事情。

在这里插入图片描述

CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {     System.out.println("  thenCompose do something 1  ");     return "1---> result"; }).thenCombine(CompletableFuture.supplyAsync(() -> {     System.out.println("  thenCompose do something 1  ");     return "2---> result";     // 第1,2个String 是返回的任务结果     // 3 个 是最后返回的类型 }), new BiFunction<String, String, String>() {     @Override     public String apply(String s, String s2) {  System.out.println("  thenCompose 里处理任务 ");  return s + " | " + s2;     } }).whenComplete((result, t) -> {     System.out.println("最后结果: " + result);     System.out.println("执行异常: " + t); }); System.out.println(stringCompletableFuture.get());

可以看到最后我们将两个任务的结果拼起来
在这里插入图片描述

allOf 与 anyOf

批量提交任务

   //返回值不确定 所以都以void返回    CompletableFuture.allOf();

在这里插入图片描述

    //提交的任务都有返回值 所以都以Object 返回    CompletableFuture.anyOf();

在这里插入图片描述
allOf的返回值是CompletableFuture类型,这是因为每个传入的CompletableFuture的返回
值都可能不同,所以组合的结果是无法用某种类型来表示的,索性返回Void类型。

anyOf 的含义是只要有任意一个 CompletableFuture 结束,就可以做接下来的事情,而无须像
AllOf那样,等待所有的CompletableFuture结束。

最后

提交给CompletableFuture执行的任务有四种类型:Runnable、Consumer、Supplier、Function。
在这里插入图片描述
runAsync 与 supplierAsync 是 CompletableFuture 的静态方法;而 thenAccept、thenAsync、thenApply是CompletableFutre的成员方法。
初始的时候没有CompletableFuture对象,也没有参数可传,所以提交的只能是Runnable或者Supplier,只能是静态方法;

通过静态方法生成CompletableFuture对象之后,便可以链式地提交其他任务了,这个时候就可以提交Runnable、Consumer、Function,且都是成员方法。