转 http://www.jianshu.com/p/6f3ee90ab7d3

CompletableFuture类实现了CompletionStage和Future接口。Future是Java 5添加的类,用来描述一个异步计算的结果,但是获取一个结果时方法较少,要么通过轮询isDone,确认完成后,调用get()获取值,要么调用get()设置一个超时时间。但是这个get()方法会阻塞住调用线程,这种阻塞的方式显然和我们的异步编程的初衷相违背。
为了解决这个问题,JDK吸收了guava的设计思想,加入了Future的诸多扩展功能形成了CompletableFuture。

CompletionStage是一个接口,从命名上看得知是一个完成的阶段,它里面的方法也标明是在某个运行阶段得到了结果之后要做的事情。

  1. 进行变换

    1. public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
    2. public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);
    3. public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);

    首先说明一下已Async结尾的方法都是可以异步执行的,如果指定了线程池,会在指定的线程池中执行,如果没有指定,默认会在ForkJoinPool.commonPool()中执行,下文中将会有好多类似的,都不详细解释了。关键的入参只有一个Function,它是函数式接口,所以使用Lambda表示起来会更加优雅。它的入参是上一个阶段计算后的结果,返回值是经过转化后结果。
    例如:

    1. @Test
    2. public void thenApply() {
    3. String result = CompletableFuture.supplyAsync(() -> "hello").thenApply(s -> s + " world").join();
    4. System.out.println(result);
    5. }

    结果为:

    1. hello world
  2. 进行消耗

    1. public CompletionStage<Void> thenAccept(Consumer<? super T> action);
    2. public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
    3. public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);

    thenAccept是针对结果进行消耗,因为他的入参是Consumer,有入参无返回值。
    例如:

    1. @Test
    2. public void thenAccept(){
    3. CompletableFuture.supplyAsync(() -> "hello").thenAccept(s -> System.out.println(s+" world"));
    4. }

    结果为:

    1. hello world
  3. 对上一步的计算结果不关心,执行下一个操作。
    1. public CompletionStage<Void> thenRun(Runnable action);
    2. public CompletionStage<Void> thenRunAsync(Runnable action);
    3. public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);

    thenRun它的入参是一个Runnable的实例,表示当得到上一步的结果时的操作。
    例如:

    1. @Test
    2. public void thenRun(){
    3. CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(2000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "hello";
    10. }).thenRun(() -> System.out.println("hello world"));
    11. while (true){}
    12. }

    结果为:

    1. hello world

    4.结合两个CompletionStage的结果,进行转化后返回

    1. public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
    2. public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
    3. public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);

    它需要原来的处理返回值,并且other代表的CompletionStage也要返回值之后,利用这两个返回值,进行转换后返回指定类型的值。
    例如:

    1. @Test
    2. public void thenCombine() {
    3. String result = CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(2000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "hello";
    10. }).thenCombine(CompletableFuture.supplyAsync(() -> {
    11. try {
    12. Thread.sleep(3000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. return "world";
    17. }), (s1, s2) -> s1 + " " + s2).join();
    18. System.out.println(result);
    19. }

    结果为:

    1. hello world
  4. 结合两个CompletionStage的结果,进行消耗
    1. public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
    2. public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
    3. public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);

    它需要原来的处理返回值,并且other代表的CompletionStage也要返回值之后,利用这两个返回值,进行消耗。
    例如:

    1. @Test
    2. public void thenAcceptBoth() {
    3. CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(2000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "hello";
    10. }).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
    11. try {
    12. Thread.sleep(3000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. return "world";
    17. }), (s1, s2) -> System.out.println(s1 + " " + s2));
    18. while (true){}
    19. }

    结果为:

    1. hello world
  5. 在两个CompletionStage都运行完执行。
    1. public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
    2. public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
    3. public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor);

    不关心这两个CompletionStage的结果,只关心这两个CompletionStage执行完毕,之后在进行操作(Runnable)。
    例如:

    1. @Test
    2. public void runAfterBoth(){
    3. CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(2000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "s1";
    10. }).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {
    11. try {
    12. Thread.sleep(3000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. return "s2";
    17. }), () -> System.out.println("hello world"));
    18. while (true){}
    19. }

    结果为

    1. hello world

    6.两个CompletionStage,谁计算的快,我就用那个CompletionStage的结果进行下一步的转化操作。

    1. public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
    2. public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
    3. public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor);

    我们现实开发场景中,总会碰到有两种渠道完成同一个事情,所以就可以调用这个方法,找一个最快的结果进行处理。
    例如:

    1. @Test
    2. public void applyToEither() {
    3. String result = CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "s1";
    10. }).applyToEither(CompletableFuture.supplyAsync(() -> {
    11. try {
    12. Thread.sleep(2000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. return "hello world";
    17. }), s -> s).join();
    18. System.out.println(result);
    19. }

    结果为:

    1. hello world
  6. 两个CompletionStage,谁计算的快,我就用那个CompletionStage的结果进行下一步的消耗操作。
    1. public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
    2. public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
    3. public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor);

    例如:

    1. @Test
    2. public void acceptEither() {
    3. CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "s1";
    10. }).acceptEither(CompletableFuture.supplyAsync(() -> {
    11. try {
    12. Thread.sleep(2000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. return "hello world";
    17. }), System.out::println);
    18. while (true){}
    19. }

    结果为:

    1. hello world
  7. 两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)。
    1. public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
    2. public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
    3. public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);

    例如:

    1. @Test
    2. public void runAfterEither() {
    3. CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "s1";
    10. }).runAfterEither(CompletableFuture.supplyAsync(() -> {
    11. try {
    12. Thread.sleep(2000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. return "s2";
    17. }), () -> System.out.println("hello world"));
    18. while (true) {
    19. }
    20. }

    结果为:

    1. hello world
  8. 当运行时出现了异常,可以通过exceptionally进行补偿。
    1. public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn);

    例如:

    1. @Test
    2. public void exceptionally() {
    3. String result = CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. if (1 == 1) {
    10. throw new RuntimeException("测试一下异常情况");
    11. }
    12. return "s1";
    13. }).exceptionally(e -> {
    14. System.out.println(e.getMessage());
    15. return "hello world";
    16. }).join();
    17. System.out.println(result);
    18. }

    结果为:

    1. java.lang.RuntimeException: 测试一下异常情况
    2. hello world
  9. 当运行完成时,对结果的记录。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。这里为什么要说成记录,因为这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常。所以不会对结果产生任何的作用。
    1. public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
    2. public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
    3. public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,Executor executor);

    例如:

    1. @Test
    2. public void whenComplete() {
    3. String result = CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. if (1 == 1) {
    10. throw new RuntimeException("测试一下异常情况");
    11. }
    12. return "s1";
    13. }).whenComplete((s, t) -> {
    14. System.out.println(s);
    15. System.out.println(t.getMessage());
    16. }).exceptionally(e -> {
    17. System.out.println(e.getMessage());
    18. return "hello world";
    19. }).join();
    20. System.out.println(result);
    21. }

    结果为:

    1. null
    2. java.lang.RuntimeException: 测试一下异常情况
    3. java.lang.RuntimeException: 测试一下异常情况
    4. hello world

    这里也可以看出,如果使用了exceptionally,就会对最终的结果产生影响,它没有口子返回如果没有异常时的正确的值,这也就引出下面我们要介绍的handle。

  10. 运行完成时,对结果的处理。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。
    1. public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
    2. public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
    3. public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);

    例如:
    出现异常时

    1. @Test
    2. public void handle() {
    3. String result = CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. //出现异常
    10. if (1 == 1) {
    11. throw new RuntimeException("测试一下异常情况");
    12. }
    13. return "s1";
    14. }).handle((s, t) -> {
    15. if (t != null) {
    16. return "hello world";
    17. }
    18. return s;
    19. }).join();
    20. System.out.println(result);
    21. }

    结果为:

    1. hello world

    未出现异常时

    1. @Test
    2. public void handle() {
    3. String result = CompletableFuture.supplyAsync(() -> {
    4. try {
    5. Thread.sleep(3000);
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "s1";
    10. }).handle((s, t) -> {
    11. if (t != null) {
    12. return "hello world";
    13. }
    14. return s;
    15. }).join();
    16. System.out.println(result);
    17. }

    结果为:

    1. s1

上面就是CompletionStage接口中方法的使用实例,CompletableFuture同样也同样实现了Future,所以也同样可以使用get进行阻塞获取值,总的来说,CompletableFuture使用起来还是比较爽的,看起来也比较优雅一点。

CompletableFuture 详解的更多相关文章

  1. Java CompletableFuture 详解

    Future是Java 5添加的类,用来描述一个异步计算的结果.你可以使用isDone方法检查计算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel方法停止任务的执 ...

  2. 【多线程】java多线程Completablefuture 详解【在spring cloud微服务之间调用,防止接口超时的应用】【未完成】

    参考地址:https://www.jianshu.com/p/6f3ee90ab7d3 示例: public static void main(String[] args) throws Interr ...

  3. Java8新特性: CompletableFuture详解

    CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调.流式处理.多个Future组合处理的能力,使Java在处理多任务的 ...

  4. Spring MVC 学习总结(二)——控制器定义与@RequestMapping详解

    一.控制器定义 控制器提供访问应用程序的行为,通常通过服务接口定义或注解定义两种方法实现. 控制器解析用户的请求并将其转换为一个模型.在Spring MVC中一个控制器可以包含多个Action(动作. ...

  5. Java基础学习总结(33)——Java8 十大新特性详解

    Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...

  6. 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术

    这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...

  7. Mysql高手系列 - 第9篇:详解分组查询,mysql分组有大坑!

    这是Mysql系列第9篇. 环境:mysql5.7.25,cmd命令中进行演示. 本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区 ...

  8. Java 异步编程 (5 种异步实现方式详解)

    ​ 同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现@mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Comp ...

  9. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

随机推荐

  1. SpringBoot 解决时区问题

    SpringBoot 解决时区问题 1.在启动类加上 @PostConstruct void setDefaultTimezone() { TimeZone.setDefault(TimeZone.g ...

  2. 内功心法 -- java.util.LinkedList<E> (4)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  3. python开发_常用的python模块及安装方法

    adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheetahcherrypy:一个WEB frameworkctype ...

  4. 九月回顾 这篇文章和ACM毫无关系= =

    其实不只是九月的回顾吧,我大概想把暑假到现在10.01发生的啥事儿都说下吧~ 嗯,我是一个比较沙茶的人,不过运气比较好吧. 高中啊,这个谈起来话就长了,在校什么风采之星大赛上,我认识了个妹子,当时感觉 ...

  5. javascript:window.history.forward(1);

    javascript:window.history.forward(1);[转] 接下来我们要讨论的方法以后退按钮本身为中心,而不是浏览器缓存.这儿有一篇文章Rewiring the Back But ...

  6. OpenWrt包管理软件opkg的使用(极路由)

    说明: 1.OpenWrt本身系统没什么问题,关键点是一些路由器尝试的限制,比如一些厂商设置成内存分区为只读,那么这个安装软件就变得没什么意义了. 2.opkg的操作有点反人类,正常步骤是查询,安装: ...

  7. php获取开始与结束日期之间所有日期的方法

    /** * 获取指定日期段内每一天的日期 * @param Date $startdate 开始日期 * @param Date $enddate 结束日期 * @return Array */ fu ...

  8. Windows UWP开发系列 – RelativePanel

    RelativePanel是在Windows 10 UWP程序中引入的一种新的布局面板,它是通过附加属性设置元素间的位置关系来对实现布局的.一个简单的示例如下: <RelativePanel&g ...

  9. 配置druid内置的log实现

    Druid不依赖任何的log组件,但支持多种log组件,会根据检测当前环境,选择一种合适的log实现. log的优先顺序 log4j -> log4j2 -> slf4j -> co ...

  10. MySQL数据库的概念

    学习数据库的一些知识.写写博客方便梳理以及巩固知识. 关于什么是数据库就举一个样例来说明,说的可能不够准确,仅仅要明确一个大概的意思就够了.深刻的学习还是要去看书的. 讲讲生活中有关数据的样例:在一个 ...