美文网首页
Java基础-线程-CompleteFuture

Java基础-线程-CompleteFuture

作者: 16325 | 来源:发表于2020-03-24 16:15 被阅读0次

Future

  • 自Java 5开始添加了Future,用来描述一个异步计算的结果。
  • 要么通过轮询isDone,确认完成后调用get()获取值,要么调用get()设置一个超时时间。但是get()方法会阻塞调用线程。
  • 对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的CPU资源,而且也不能及时地得到计算结果。
  • 为什么不能用观察者设计模式当计算结果完成及时通知监听者呢?

为了解决这个问题,自Java 8开始,吸收了guava的设计思想,加入了Future的诸多扩展功能形成了CompletableFuture。

CompletableFuture

  • CompletableFuture类实现了CompletionStage和Future接口,所以你还是可以像以前一样通过阻塞或者轮询的方式获得结果,尽管这种方式不推荐使用。

创建CompletableFuture对象

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {
    return asyncSupplyStage(screenExecutor(executor), supplier);
}

public static CompletableFuture<Void> runAsync(Runnable runnable) {
    return asyncRunStage(asyncPool, runnable);
}

public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) {
    return asyncRunStage(screenExecutor(executor), runnable);
}

以Async结尾并且没有指定Executor的方法会使用ForkJoinPool.commonPool()作为线程池执行异步代码。

  • runAsync方法用于没有返回值的任务,它以Runnable函数式接口类型为参数,所以CompletableFuture的计算结果为空。
  • supplyAsync方法用于有返回值的任务,以Supplier<U>函数式接口类型为参数,CompletableFuture的计算结果类型为U。

计算结果完成时的处理

当CompletableFuture的计算结果完成,或者抛出异常的时候,有如下四个方法:

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);
}
public CompletableFuture<T> exceptionally(
    Function<Throwable, ? extends T> fn) {
    return uniExceptionallyStage(fn);
}
  • 方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
  • exceptionally方法返回一个新的CompletableFuture,当原始的CompletableFuture抛出异常的时候,就会触发这个CompletableFuture的计算,调用function计算值,否则如果原始的CompletableFuture正常计算完后,这个新的CompletableFuture也计算完成,它的值和原始的CompletableFuture的计算的值相同。
  • 除了上述四个方法之外,一组handle方法也可用于处理计算结果。当原先的CompletableFuture的值计算完成或者抛出异常的时候,会触发这个CompletableFuture对象的计算,结果由BiFunction参数计算而得。因此这组方法兼有whenComplete和转换的两个功能。
public <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn);

public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn);

public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor);

进行转换

我们可以将操作串联起来,或者将CompletableFuture组合起来。关键的入参只有一个Function,它是函数式接口,所以使用Lambda表示起来会更加优雅。它的入参是上一个阶段计算后的结果,返回值是经过转化后结果。

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

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

public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
  • 函数的功能是当原来的CompletableFuture计算完后,将结果传递给函数fn,将fn的结果作为新的CompletableFuture计算结果。因此它的功能相当于将CompletableFuture<T>转换成CompletableFuture<U>。
  • 需要注意的是,这些转换并不是马上执行的,也不会阻塞,而是在前一个stage完成后继续执行。

消费

上面的方法是当计算完成的时候,会生成新的计算结果(thenApply, handle),或者返回同样的计算结果whenComplete。我们可以在每个CompletableFuture 上注册一个操作,该操作会在 CompletableFuture 完成执行后调用它。

public CompletableFuture<Void> thenAccept(Consumer<? super T> action);

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action);

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor);
  • CompletableFuture 通过 thenAccept 方法提供了这一功能,它接收CompletableFuture 执行完毕后的返回值做参数,只对结果执行Action,而不返回新的计算值,因此计算值为空:
  • 下面一组方法当计算完成的时候会执行一个Runnable,与thenAccept不同,Runnable并不使用CompletableFuture计算的结果。
public CompletableFuture<Void> thenRun(Runnable action);

public CompletableFuture<Void> thenRunAsync(Runnable action);

public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor);

组合

通常,我们会有多个需要独立运行但又有所依赖的的任务。比如先等用于的订单处理完毕然后才发送邮件通知客户。

thenCompose 方法允许你对两个异步操作进行流水线,第一个操作完成时,将其结果作为参数传递给第二个操作。你可以创建两个CompletableFutures 对象,对第一个 CompletableFuture 对象调用thenCompose ,并向其传递一个函数。当第一个CompletableFuture 执行完毕后,它的结果将作为该函数的参数,这个函数的返回值是以第一个 CompletableFuture 的返回做输入计算出的第二个 CompletableFuture 对象。

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

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

public <U> CompletableFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn, Executor executor);

相关文章

  • Java基础-线程-CompleteFuture

    Future 自Java 5开始添加了Future,用来描述一个异步计算的结果。 要么通过轮询isDone,确认完...

  • 技术体系

    一,java核心 java基础,jvm,算法,多线程,设计模式 Java基础:java基础相关,全栈java基础 ...

  • Java多线程目录

    Java多线程目录 Java多线程1 线程基础Java多线程2 多个线程之间共享数据Java多线程3 原子性操作类...

  • android 多线程 — 线程的面试题和答案

    这里都是我从各个地方找来的资料,鸣谢: Java多线程干货系列—(一)Java多线程基础 JAVA多线程和并发基础...

  • Android中的多线程

    1. Java多线程基础 Java多线程,线程同步,线程通讯 2. Android常用线程 HandlerThre...

  • Java基础

    Java基础 集合基础 集合框架 多线程基础 多线程框架 反射 代理 集合基础 ArrayList LinkedL...

  • java基础知识11-completeFuture

    1. callable runnable future Callable,有结果的同步行为,比如做蛋糕,产生蛋糕R...

  • java多线程相关

    (一) 基础篇 01.Java多线程系列--“基础篇”01之 基本概念 02.Java多线程系列--“基础篇”02...

  • java线程入门基础(二)

    java线程入门基础(二) 一、认识Java里的线程 1.1 Java里的程序天生就是多线程的 一个Java程序从...

  • Java多线程高级特性(JDK8)

    [TOC] 一、Java多线程 1.Java多线程基础知识 Java 给多线程编程提供了内置的支持。一条线程指的是...

网友评论

      本文标题:Java基础-线程-CompleteFuture

      本文链接:https://www.haomeiwen.com/subject/ujnoyhtx.html