JDK1.8新特性CompletableFuture总结

CompletableFuture这个completableFuture是JDK1.8版本新引入的类。下面是这个类。实现了俩接口。本身是个class。这个是Future的实现类。使用completionStage接口去支持完成时触发的函数和操作。一个completetableFuture就代表了一个任务。他能用Future的方法。还能做一些之前说的executorService配合fu…

大家好,又见面了,我是你们的朋友全栈君。

CompletableFuture

这个completableFuture是JDK1.8版本新引入的类。下面是这个类。实现了俩接口。本身是个class。这个是Future的实现类。

使用completionStage接口去支持完成时触发的函数和操作。

一个completetableFuture就代表了一个任务。他能用Future的方法。还能做一些之前说的executorService配合futures做不了的。

之前future需要等待isDone为true才能知道任务跑完了。或者就是用get方法调用的时候会出现阻塞。而使用completableFuture的使用就可以用then,when等等操作来防止以上的阻塞和轮询isDone的现象出现。

JDK1.8新特性CompletableFuture总结

1. 创建CompletableFuture直接new对象也成。一个completableFuture对象代表着一个任务。这个对象能跟这个任务产生联系。下面用的complete方法意思就是这个任务完成了需要返回的结果。然后用get();方法可以获取到。

JDK1.8新特性CompletableFuture总结

2.JDK1.8使用的接口类。在本文的CompletableFuture中大量的使用了这些函数式接口。

注:这些声明大量应用于方法的入参中。像thenApply和thenAccept这俩就是一个用Function一个用Consumer

而lambda函数正好是可以作为这些接口的实现。例如 s->{return 1;} 这个就相当于一个Function。因为有入参和返回结果。

JDK1.8新特性CompletableFuture总结

(1)Function

JDK1.8新特性CompletableFuture总结

(2)Consumer

JDK1.8新特性CompletableFuture总结

对于前面有Bi的就是这样的。BiConsumer就是两个参数的。

JDK1.8新特性CompletableFuture总结

(3)Predicate这个接口声明是一个入参,返回一个boolean。

JDK1.8新特性CompletableFuture总结

(4)supplier

JDK1.8新特性CompletableFuture总结

3. 下面是这个类的静态方法。带有Async就是异步执行的意思、也是一个completableFuture对象代表着一个任务这个原则。

这种异步方法都可以指定一个线程池作为任务的运行环境。如果没有指定就会使用ForkJoinPool线程池来执行、

JDK1.8新特性CompletableFuture总结

(1)supplyAsync&runAsync的使用例子。

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.submit(new Callable<Object>() {
        @Override
        public Object call() throws Exception {
            System.out.println("executorService 是否为守护线程 :" + Thread.currentThread().isDaemon());
            return null;
        }
    });
    final CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("this is lambda supplyAsync");
        System.out.println("supplyAsync 是否为守护线程 " + Thread.currentThread().isDaemon());
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("this lambda is executed by forkJoinPool");
        return "result1";
    });
    final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("this is task with executor");
System.out.println("supplyAsync 使用executorService 时是否为守护线程 : " + Thread.currentThread().isDaemon());
        return "result2";
    }, executorService);
    System.out.println(completableFuture.get());
    System.out.println(future.get());
    executorService.shutdown();
}

JDK1.8新特性CompletableFuture总结

注意:这些任务中。带有supply是持有返回值的,run是void返回值的。在玩supply时发现一个问题如果使用supplyAsync任务时不使用任务的返回值。即不用get方法阻塞主线程会导致任务执行中断。(注:跟get方法无关,后面有答案)

JDK1.8新特性CompletableFuture总结

JDK1.8新特性CompletableFuture总结

然后我开始探索是否是只有supplyAsync是这样。我测试了runAsync发现也是这样。

JDK1.8新特性CompletableFuture总结

下图为与supplyAsync任务执行不全面一样的问题。我甚至测试了将lambda换成runnable发现无济于事。

JDK1.8新特性CompletableFuture总结

答案:

造成这个原因是因为Daemon。因为completableFuture这套使用异步任务的操作都是创建成了守护线程。那么我们没有调用get方法不阻塞这个主线程的时候。主线程执行完毕。所有线程执行完毕就会导致一个问题,就是守护线程退出。那么我们没有执行的代码就是因为主线程不再跑任务而关闭导致的。可能这个不叫问题,因为在开发中我们主线程常常是一直开着的。但是这个小问题同样让我想了好久。下面我们开一个非守护线程,可以看到程序执行顺利。

JDK1.8新特性CompletableFuture总结

下面证实守护线程在其他非守护线程全部退出的情况下不继续执行。

final CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
    System.out.println("this is lambda supplyAsync");
    System.out.println("supplyAsync 是否为守护线程 " + Thread.currentThread().isDaemon());
    try {
        TimeUnit.SECONDS.sleep(1);
        try(BufferedWriter writer = new BufferedWriter
                (new OutputStreamWriter(new FileOutputStream(new File("/Users/zhangyong/Desktop/temp/out.txt"))))){
            writer.write("this is completableFuture daemon test");
        }catch (Exception e){
            System.out.println("exception find");
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("this lambda is executed by forkJoinPool");
    return "result1";
});

这个代码就是操作本地文件。并且sleep了一秒。其他线程就一句控制台输出的代码。最终的结果是文件没有任何变化。

当我把主线程sleep 5秒时。本地文件会写入一句  this is completableFuture daemon test   验证成功。

(2)allOf&anyOf

这两个方法的入参是一个completableFuture组、allOf就是所有任务都完成时返回。但是是个Void的返回值。

anyOf是当入参的completableFuture组中有一个任务执行完毕就返回。返回结果是第一个完成的任务的结果。

public static void otherStaticMethod() throws ExecutionException, InterruptedException {
        final CompletableFuture<String> futureOne = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("futureOne InterruptedException");
            }
            return "futureOneResult";
        });
        final CompletableFuture<String> futureTwo = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                System.out.println("futureTwo InterruptedException");
            }
            return "futureTwoResult";
        });
        CompletableFuture future = CompletableFuture.allOf(futureOne, futureTwo);
        System.out.println(future.get());
//        CompletableFuture completableFuture = CompletableFuture.anyOf(futureOne, futureTwo);
//        System.out.println(completableFuture.get());
    }

JDK1.8新特性CompletableFuture总结

JDK1.8新特性CompletableFuture总结

(3)completedFuture这个方法我没懂他是干啥的。源码就是返回一个值。感觉没啥意义。

JDK1.8新特性CompletableFuture总结

(4)取值方法,除了get还有一个getNow(); 这个就比较特殊了。 这个方法是执行这个方法的时候任务执行完了就返回任务的结果,如果任务没有执行完就返回你的入参。

JDK1.8新特性CompletableFuture总结

(5)join方法跟线程的join用法差不多。

JDK1.8新特性CompletableFuture总结

(6)whenXXX,在一个任务执行完成之后调用的方法。

这个有三个名差不多的方法。whenComplete、whenCompleteAsync、还有一个是whenCompleteAsync用自定义Executor

JDK1.8新特性CompletableFuture总结

首先看一下这个whenComplete实例方法。这个就是任务执行完毕调用的,传入一个action。这个方法的执行线程是当前线程,意味着会阻塞当前线程。下面图中test的输出跟whenComplete方法运行的线程有关。运行到main线程就会阻塞test的输出。运行的是completableFuture线程则不会阻塞住test的输出。

JDK1.8新特性CompletableFuture总结

下面是任务执行的线程的探索。

JDK1.8新特性CompletableFuture总结

JDK1.8新特性CompletableFuture总结

根据测试得出的结论是:如果调用whenComplete的中途,还发生了其他事情,图中的主线程的sleep(400);导致completableFuture这个任务执行完毕了,那么就使用主线程调用。如果调用的中途没有发生其他任务且在触碰到whenComplete方法时completableFuture这个任务还没有彻底执行完毕那么就会用completableFuture这个任务所使用的线程。

 

下面是whenCompleteAsync方法。这个方法就是新创建一个异步线程执行。所以不会阻塞。

JDK1.8新特性CompletableFuture总结

(7) then。方法瞅着挺多的。实际上就是异不异步和加不加自定义Executor.

JDK1.8新特性CompletableFuture总结

注:whenComplete中出现的问题在then中测试不存在、使用的就是上一个任务的线程。这个thenCompose就是一个任务执行完之后可以用它的返回结果接着执行的方法。方法返回的是另一个你期盼泛型的结果、

compose理解就是上一个任务结果是then的一部分。

JDK1.8新特性CompletableFuture总结

下面介绍一下thenCombine。这个combine的理解就是结合两个任务的结果。

JDK1.8新特性CompletableFuture总结

综上:这个线程的问题并不是大问题,只要你不用线程来做判断条件。他并不会影响你的效率。试想pool线程都执行完了就用主线程跑呗。没跑完,而使你等了那你就用pool线程呗。

thenRun就是这个任务运行完,再运行下一个任务。感觉像是join了一下。

JDK1.8新特性CompletableFuture总结

其余不再介绍。大同小异。

像thenApply(Function);这样的就是有入参有返回值类型的。

像thenAccept(Consumer);这样的就是有入参,但是没有返回值的。详情在上文中有过关于函数式接口的叙述。

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/124952.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Java线程池面试题

    1、什么是线程池2、常见线程池

  • springboot的介绍_springboot官网

    springboot的介绍_springboot官网Springboot入门介绍一、Spring框架概述1.1什么是SpringSpring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由RodJohnson在其著作《ExpertOne-On-OneJ2EEDevelopmentandDesign》。Spring是为了解决企业级应用开发的复杂性而创建的,使用Spring可以让简单的Ja…

  • 2020最新Java面试题(常见面试题及答案汇总)「建议收藏」

    2020最新Java面试题(常见面试题及答案汇总)「建议收藏」Java基础篇1.JDK和JRE的区别是什么?JDK:JavaDevelopmentKit的简称,java开发工具包,提供了java的开发环境和运行环境。JRE:JavaRuntimeEnvironment的简称,java运行环境,为java的运行提供了所需环境。总结:JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含…

  • j2EE是什么_j2ee体系结构

    j2EE是什么_j2ee体系结构经过本次学习,我们知道了J2EE的整体架构以及一些核心的组件,更加理解了其伸缩性、灵活性和易维护性,这对我们以后的学习会有很大的帮助.当然,我们学过了这些基本的概念之后,最主要的还是要在实际运用中去体会,去总结,然后再返回来看这些东西,我们就会有很大的收获。这就是一个学习的过程,加油。

    2022年10月11日
  • scrollwidth和clientwidth_vue监听页面滚动

    scrollwidth和clientwidth_vue监听页面滚动本文并非原创,只是真心觉得好,特别是图解的很到位,我在js中经常会用到,就记下来,与大家分享。HTML:scrollLeft,scrollWidth,clientWidth,offsetWidth到底指的哪到哪的距离之完全详解scrollHeight:获取对象的滚动高度。scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离scrollTo

  • 三款免费好用的Gif录屏神器

    1.免费开源的GIF录制工具ScreenToGif官网地址:http://www.screentogif.com/ScreenToGif,国外免费开源小巧实用的Gif动画录制工具!使用ScreenToGif,可以将屏幕任何区域及操作过程录制成GIF格式的动画图像,保存过程还可以对GIF动画进行编辑优化。这款非常优秀的工具原生单执行文件,界面非常简单,功能很实用,它具有录制屏幕、录制摄像…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号