JUC之CompletableFuture

这篇具有很好参考价值的文章主要介绍了JUC之CompletableFuture。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Future接口理论

Future接口定义了异步任务执行的一些方法,包括异步任务执行结果,异步任务执行是否中断,异步任务是否完毕等。

Future接口常用实现类FutureTask异步任务

        FutureTask<String> futureTask = new FutureTask<String>( () -> {
            System.out.println(Thread.currentThread().getName()+"\t -----come in");
            try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
            return "task over";
        });
        Thread t1 = new Thread(futureTask, "t1");
        t1.start();

CompletableFuture

CompletableFuture对Future的改进

  • CompletableFuture异步线程发生异常,不会影响到主线程,用来记录日志特别方便。
  • CompletableFuture出现的原因:Future的get方法是阻塞方法,当异步线程计算完成之前一直会阻塞,isDone()方法判断异步线程又特别消耗CPU资源。对于真正的异步处理我们希望传入回调函数,在Future结束时,自动调用该回调函数。这样我们就不用等待结果 。
  • CompletableFuture提供了一种观察者模式,可以让任务完成后通知监听的一方。
    JUC之CompletableFuture,JUC,java,数据库,linux

CompletionStage

  • CompltionStage是异步执行的一个阶段。一个阶段执行完成之后可能触发另一个阶段。
  • 一个阶段的执行可以是一个Function,Comsumer或者Runnable。比如
 stage.thenApply(x -> square(x)).thenAccept(×->System.out.print(x)).thenRun(( ->system.out.println())
  • 一个阶段可能会是另一个阶段完成后触发。也可能是其他多个阶段完成后触发。

CompletableFuture的方法

JUC之CompletableFuture,JUC,java,数据库,linux
主要是runAsync和supplyAsnc方法。一个无返回值。一个有返回值。

CompletableFuture的优点

  • 异步任务执行完成后,会自动调用某个对象的方法
  • 异步任务出异常后,会自动调用某个对象的方法
  • 主线程设置好回调后,不用关心异步任务的执行。异步任务之间可以顺序执行。

案例 - 前言

join和get的区别。get必须处理异常。join不需要处理异常
jdk8新特性: lambda表达式,stream流,chain链式调用,函数式编程
JUC之CompletableFuture,JUC,java,数据库,linux
有参数,有返回值:Function
有参数,无返回值:Consume, BiConsumer(两个参数)
无参数,有返回值:Supplier
无参数,无返回值:Runnable

案例-从电商网站的比价需求

原来的写法,串行的方式

    /**
     * step by step 一家家搜查
     * List<NetMall> ----->map------> List<String>
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPrice(List<NetMall> list,String productName)
    {
        //《mysql》 in taobao price is 90.43
        return list
                .stream()
                .map(netMall ->
                        String.format(productName + " in %s price is %.2f",
                                netMall.getNetMallName(),
                                netMall.calcPrice(productName)))
                .collect(Collectors.toList());
    }

使用CompletableFuture,异步的方式

 /**
     * List<NetMall> ----->List<CompletableFuture<String>>------> List<String>
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPriceByCompletableFuture(List<NetMall> list,String productName)
    {
        return list.stream().map(netMall ->
                CompletableFuture.supplyAsync(() -> String.format(productName + " in %s price is %.2f",
                netMall.getNetMallName(),
                netMall.calcPrice(productName))))
                .collect(Collectors.toList())
                .stream()
                .map(s -> s.join())
                .collect(Collectors.toList());
    }

耗时:比串行的方式快得多!!!

CompletableFuture 常用方法

获得结果和触发计算

获得结果:

  • public T get() 一直等
  • public T get(long timeout,TimeUnit unit) 过时不候,到了时间没拿到结果会报异常
  • public T join():join和get都是用来获取CompletableFuture异步之后的返回值。join是unchecked异常(即运行时异常)。get是checked异常(经过检查的异常)
  • public T getNow(T valuelfAbsent):没有计算完,给我默认的结果。计算完,返回实际的结果。

主动触发计算:

  • public boolean complete(T value) 如果CompletableFuture没有完成,将get结果修改为value,返回值为true。如果完成了,不修改get,返回值为false.
public class CompletableFutureTest {

  public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
      CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
          try {
              Thread.sleep(2000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          return "hello CompletableFuture";
      });

      System.out.println(completableFuture.getNow("心急吃不了热豆腐"));
      System.out.println(completableFuture.get());
      System.out.println(completableFuture.get(1500, TimeUnit.MILLISECONDS));
      System.out.println(completableFuture.join());
      System.out.println(completableFuture.complete("未雨绸缪")+"\t"+completableFuture.join());

  }
}

对计算结果进行处理

thenApply(常用)

两个计算结果存在依赖关系,这两个线程串行化。
出现异常,直接跳到whenComplete和exceptionally执行。(不再执行后续的thenApply)

public class CompletableFutureTest2 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 6;
        },executorService).thenApply((r)-> {
            int i=2/0;
            return r * 5;
        }).thenApply((r)-> {
            System.out.println(r);
            return r - 2;
        }).whenComplete((v, e) -> {
            System.out.println("计算结果:"+v);
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            System.out.println(e);
            return null;
        });
        System.out.println("============主线程==========");
        executorService.shutdown();
    }
}

handle

计算机结果存在依赖关系,两个线程串行化
handle出现异常,会往下一个handle走,同时也会走到whenComplete和exceptionally

public class CompletableFutureTest2 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 6;
        },executorService).handle((r,e)-> {
            int i=2/0;
            return r * 5;
        }).handle((r,e)-> {
            System.out.println(r);
            return r - 2;
        }).whenComplete((v, e) -> {
            System.out.println("计算结果:"+v);
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            System.out.println(e);
            return null;
        });
        System.out.println("============主线程==========");
        executorService.shutdown();
    }
}

exceptionally相当于try catch
whenComplete和handler相当于try finally
JUC之CompletableFuture,JUC,java,数据库,linux

对计算结果进行消费

接受任务的处理结果,消费处理。thenAccept无返回结果。(thenApply是有返回结果的)

public class CompletableFutureTest3 {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(()->{
            return 3;
        }).thenApply(r->{
            return r*8;
        }).thenApply(r->{
            return r/2;
        }).thenAccept(r-> System.out.println(r));
        System.out.println(CompletableFuture.supplyAsync(()->"6666").thenRun(()->{}).join());
        System.out.println(CompletableFuture.supplyAsync(()->"6666").thenAccept(r-> System.out.println(r)).join());
        System.out.println(CompletableFuture.supplyAsync(()->"6666").thenApply(r->r+"9999").join());
    }
}

12
null
6666
null
66669999

对计算速度进行选用与对计算结果进行合并

applyToEither:谁快用谁
thenCombine: 两个completionStage任务都完成后,将结果交给thenCombine。先完成的先等着,等待其他分支任务。

public class CompletableFutureTest4 {
    public static void main(String[] args) {
        CompletableFuture<String> first = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "1号选手";
        });
        CompletableFuture<String> second = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "2号选手";
        });
        CompletableFuture<String> result = first.applyToEither(second, r -> r + "is winner");
        CompletableFuture<String> res = first.thenCombine(second, (x, y) -> x + y);
        System.out.println(result.join());
        System.out.println(res.join());
    }
}

并行执行

allOf():当所有给定的CompletableFuture完成时, 返回一个新的CompletableFuture
anyOf():当任何一个给定的CompletableFuture完成时,返回一个新的CompletableFuture

	public static void testAllOf(){
        CompletableFuture<String> future1 = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future1执行完成");
        });

        CompletableFuture<String> future2 = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future2执行完成");
        });

        CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);
			try {
            all.get(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
    }

completableFuture和线程池说明

以thenRun和thenRunAsync为例,有什么区别?文章来源地址https://www.toymoban.com/news/detail-795722.html

  • 没有传入自定义线程池,默认是ForkJoinPool.
  • 如果第一个执行的任务传入了一个自定义线程池,调用thenRun执行第二个任务,则第一个和第二个都是用自定义的线程池。
  • 如果第一个执行的任务传入了一个自定义线程池,调用thenRunAsyn执行第二个任务,则第一个用自定义。第二个用ForkJoinPool(后面也都是ForkJoinPool)

到了这里,关于JUC之CompletableFuture的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [开发|数据库] java程序人大金仓数据库适配笔记

    需要去人大金仓https://www.kingbase.com.cn/qd/index.htm下载linux版iso文件和授权文件(license-企业版-90天)。 iso文件需要挂载在指定目录下。 参考:(https://www.cnblogs.com/bluestorm/p/16941812.html)。 人大金仓数据库安装过程中出现乱码/内容不显示是因为jdk版本不匹配,通过asdf更换java版本为

    2024年02月12日
    浏览(53)
  • 【数据库】Java的JDBC编程(idea链接数据库)

    目录 前言 1、Java的数据库编程:JDBC    2、使用JDBC(项目中导入数据库驱动包) 2.1、获取驱动包 2.2、将数据库驱动包导入Java项目中 2.3、使用JDBC编写代码 2.3.1、创建并初始化一个数据源 2.3.2、 和数据库服务器建立链接 2.3.3、构建SQL语句  2.3.4、执行SQL语句  2.3.4、释放资源

    2024年02月02日
    浏览(51)
  • java批量修改数据库数据

    批量更新 mysql更新语句很简单,更新一条数据的某个字段,一般这样写: 代码如下: UPDATE mytable SET myfield = ‘value’ WHERE other_field = ‘other_value’; 如果更新同一字段为同一个值,mysql也很简单,修改下where即可: 代码如下: UPDATE mytable SET myfield = ‘value’ WHERE other_field in (‘oth

    2024年02月16日
    浏览(47)
  • java数据库操作

    数据库访问几乎每一个稍微成型的程序都要用到的知识,怎么高效的访问数据库也是我们学习的一个重点,今天的任务就是总结java访问数据库的方法和有关API,java访问数据库主要用的方法是JDBC,它是java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸

    2024年02月10日
    浏览(29)
  • 数据库--教务管理系统(数据库部分--Java-jdbc连接)

    我所设计的教务管理系统包括6大部分,学生信息、教师信息、课程信息、班级信息、选课信息、教授信息。该系统可以通过不同的群体进行操作:学生群体可以对个人信息、班级、教师信息进行查询操作,对于课程则可以进行选课操作;教师群体可以个人信息、班级信息、学

    2024年02月03日
    浏览(60)
  • Java常用数据库列表

    1、MySQL MySQL是一种开源的关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现在由Oracle公司负责维护和支持。MySQL是最流行的数据库之一,被广泛用于各种应用程序和网站开发。 MySQL具有以下特点: 开源性:MySQL是开源软件,可以免费获取并自由使用、修改和分发。

    2024年02月12日
    浏览(31)
  • JAVA面试数据库篇

    目录 数据库篇 一.优化 1.定位慢查询 MYSQL中,如何定位慢查询? 2.SQL执行计划 SQL语句执行慢,如何分析呢? 3.索引 了解过索引吗?(什么是索引) 索引的底层数据结构了解过吗? B树和B+树的区别是什么呢? 什么是聚簇索引什么是非聚簇索引?/什么是聚集索引,什么是二级索

    2024年02月13日
    浏览(34)
  • Java读取数据库表

    Java自带的日志。 常见用法如下,打印日志信息: logger.error(\\\"数据库连接失败\\\",e) logger.info(\\\"tableName:{},comment:{}\\\",tableName,comment),{}是占位符 指定类初始化日志对象,在日志输出的时候,可以打印出日志信息所在类。 Connection 对象用于打开与数据源的连接。 加载驱动程序。 获取

    2024年02月02日
    浏览(35)
  • JAVA整合Milvus矢量数据库及数据

      背景:目前milvsu版本迭代至2.0,已经可以支持直接在docker环境下运行 目录 一、Milvus的基本情况 什么是 Milvus 向量数据库? 非结构化数据 特征向量 向量相似度检索 为什么选择使用 Milvus? 二、Milvus的下载安装 安装前提 硬件要求 软件要求 Milvus下载安装 Milvus矢量库的可视化

    2024年02月15日
    浏览(41)
  • Java分批将List数据导入数据库

    在工作中的一个需求中,需要创建一张新的表,表格的初始数据需要从之前的多张表格中联查出来并且添加到当前表格中。由于在生产环境中数据量级达到了 百万级别 ,因此在插入数据到MySQL中时需要 分批次进行导入 ,我写了三种方法进行数据的导入,最后采用了第三种方

    2024年02月16日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包