• JDK1.8新特性CompletableFuture


    为什么需要线程池

            当我们需要异步处理任务时,最常用也是最简单的方式就是新开一个线程去做。而线程的创建和销毁是需要消耗 CPU 资源的,当异步任务越来越多时,如果一味的新开线程去处理,那么我们可能会无法控制 CPU 的资源。所以首先我们需要控制线程的开启数量。

            类比数据库连接池,想一想之前使用 JDBC 访问数据库的时候是不是要先建立连接,也就是创建一个 Connection 对象。在 web 项目中,通常会有很多请求访问数据库,在使用框架 Spring+Mybatis 时,如果当前上下文没有事务的话那么每一个数据库操作方法都需要创建一个 Connection,这样频繁的创建 Connection 对象无疑是资源的浪费,也会拉低接口吞吐量。所以我们需要一个池子来维护数据库连接,也就是数据库连接池。同样我们也需要线程池。

    CompletableFuture介绍

    JDK1.8 中提供的 CompletableFuture 提供了异步函数式编程。可以帮助我们简化异步编程的复杂性,通过回调的方式处理计算结果,并且提供了转换和组合的方法。

    CompletableFuture是JDK1.8版本新引入的类,使用completionStage接口去支持完成时触发的函数和操作。

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

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

    CompletableFuture 的使用

    (1)创建 CompletableFuture 对象

    提供了四个静态方法来创建:

    1. public static CompletableFuture runAsync(Runnable runnable)
    2. public static CompletableFuture runAsync(Runnable runnable, Executor executor)
    3. public static CompletableFuture supplyAsync(Supplier supplier)
    4. public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)
    • supply开头:这种方法,可以返回异步线程执行之后的结果
    • run开头:这种不会返回结果,就只是执行线程任务

    默认使用ForkJoinPool.commonPool(), commonPool是一个会被很多任务共享的线程池,比如同一JVM上的所有CompletableFuture、并行Stream都将共享commonPoolcommonPool设计时的目标场景是运行非阻塞的CPU密集型任务,为最大利用CPU,其线程数默认为CPU数量-1。

    (2)阻塞获取

    以下四个方法用于获取结果:

    1. public T get()
    2. public T get(long timeout, TimeUnit unit)
    3. public T getNow(T valueIfAbsent)
    4. public T join()
    • getNow() 代表计算完,如果返回结果或抛出异常就正常get,否则就返回给定的 valueIfAbsent 值
    • join() 返回计算的结果或者抛出一个 unchecked 异常(CompletionException)
    • get() 方法调用的时候会出现阻塞

    (3)计算完成时处理

    这四个方法是计算阶段结束的时候触发

    1. public CompletableFuture whenComplete(BiConsumersuper T,? super Throwable> action)
    2. public CompletableFuture whenCompleteAsync(BiConsumersuper T,? super Throwable> action)
    3. public CompletableFuture whenCompleteAsync(BiConsumersuper T,? super Throwable> action, Executor executor)
    4. public CompletableFuture exceptionally(Function fn)

    常用方法

    1、thenCompose

     thenCompose方法会在某个任务执行完成后,将该任务的执行结果,作为方法入参,去执行指定的方法。该方法会返回一个新的CompletableFuture实例

    • 如果该CompletableFuture实例的result不为null,则返回一个基于该result新的CompletableFuture实例;
    • 如果该CompletableFuture实例为null,然后就执行这个新任务。
    1. public static void main(String[] args) {
    2. SmallTool.printTimeAndThread("小白进入餐厅");
    3. SmallTool.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");
    4. CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
    5. SmallTool.printTimeAndThread("厨师炒菜");
    6. SmallTool.sleepMillis(200);
    7. return "番茄炒蛋";
    8. }).thenCompose(dish -> CompletableFuture.supplyAsync(() -> {
    9. SmallTool.printTimeAndThread("服务员打饭");
    10. SmallTool.sleepMillis(100);
    11. return dish + "米饭";
    12. }));
    13. SmallTool.printTimeAndThread("小白在打王者");
    14. SmallTool.printTimeAndThread(String.format("%s ,小白开吃 ", cf1.join()));
    15. }

    结果输出:

     

    2、thenCombine

    会将两个任务的执行结果作为方法入参,传递到指定方法中,且有返回值。

    1. public static void main(String[] args) {
    2. SmallTool.printTimeAndThread("小白进入餐厅");
    3. SmallTool.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");
    4. CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
    5. SmallTool.printTimeAndThread("厨师炒菜");
    6. SmallTool.sleepMillis(200);
    7. return "番茄炒蛋";
    8. }).thenCombine(CompletableFuture.supplyAsync(() -> {
    9. SmallTool.printTimeAndThread("服务器蒸饭");
    10. SmallTool.sleepMillis(300);
    11. return "米饭";
    12. }), (dish, rice) -> {
    13. SmallTool.printTimeAndThread("服务器打饭");
    14. SmallTool.sleepMillis(100);
    15. return String.format("%s + %s 好了", dish, rice);
    16. });
    17. SmallTool.printTimeAndThread("小白在打王者");
    18. SmallTool.printTimeAndThread(String.format("%s ,小白开吃", cf1.join()));
    19. }

    结果输出:

     

    参考文档:

    1、CompletableFuture 使用及应用场景_再见丶孙悟空的博客-CSDN博客_completablefuture使用场景
    2、JDK1.8新特性CompletableFuture总结_finalheart的博客-CSDN博客_completablefuture

    学习视频推荐:

    1、CompletableFuture学习视频  :https://www.bilibili.com/video/BV1ar4y1x727?p=12&vd_source=13c57fbfc572ebd03c0f07686c93ce64

    2、B站 CompletableFuture学习 :https://www.bilibili.com/video/BV1ui4y1T7xf/?spm_id_from=pageDriver&vd_source=7c9c5325e34e359ba5671d7a733fcfd3

     

  • 相关阅读:
    JavaScript 语法基础
    Vue3,Typescript中引用组件路径无法找到模块报错
    消息中间件篇之Kafka-数据清理机制
    第2章 控制结构和函数(编程题)
    生命不息,分享不止,5款小巧的免费软件
    Go语言学习笔记-A Tour of Go 练习笔记-Errors
    Java笔记(4)
    1017 A除以B
    Elasticsearch
    Tomcat详解
  • 原文地址:https://blog.csdn.net/Sophia_0331/article/details/126696454