CompleteFuture实现简单的任务编排实践

一:前言

​ CompleteFuture是java8 新提供的API,是对函数式编程思想的体现,提供了很多的对于函数式编程支持。不止有同步处理功能,还有异步处理能力。

通过函数式编程可以实现线程的简单任务编排。高效,整洁实现多线程异步编程。

二:详细介绍

CompleteFuture 提供的API中以ansy结尾的都是异步处理的。

  1. 异步执行任务,并返回结果:supplyAsync 异步处理,并返回结果,默认使用 ForkJoinPool.commonPool()线程池,同时提供支持自定义线程池的API。

    1. CompletableFuture.supplyAsync(() -> "HELLO");
    2. // 自定义线程池
    3. CompletableFuture.supplyAsync(()->"hello",ES);
    1. 异步执行任务,不返回结果:runAsync
    1. CompletableFuture.runAsync(() -> System.out.println("HELLO WORLD !"));
    2. CompletableFuture.runAsync(() -> System.out.println("HELLO WORLD !"),ES);
    1. 依赖单一阶段:thenApply thenApplyAsync
    1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "HELLO")
    2. .thenApply(a ->
    3. return a + " lili!";
    4. });
    1. 组合与撰写:thenCompose()thenCombine()thenCombineAsync.
    1. CompletableFuture<String> f1 =
    2. CompletableFuture.supplyAsync(() -> "hello")
    3. .thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lili"))
    4. .thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lucy"));
    5. // 执行结果: =====> hello lili lucy
    6. // mian线程下同步执行。
    1. CompletableFuture<String> f1 =
    2. CompletableFuture.supplyAsync(() -> "hello")
    3. .thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lili"))
    4. .thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lucy"))
    5. .thenCombineAsync(CompletableFuture.supplyAsync(() -> " how are you!"), (a, b) -> a + b);
    6. log.info("=====> {}", f1.get());
    7. // 执行结果: =====> hello lili lucy how are you!
    1. 依赖两个任务中的一个:applyToEither() ,那个任务先结束,就依赖那个任务。
    1. CompletableFuture<String> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
    2. try {TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace();}
    3. return "lucy";
    4. }).applyToEither(CompletableFuture.supplyAsync(() -> {
    5. try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
    6. return "lili";
    7. }), a -> "hello " + a);
    8. log.info("ret ====> {}",voidCompletableFuture.get());
    9. // 执行结果: ret ====> hello lili 如果下面sleep改成3s,执行结果:ret ====> hello lucy
    1. 消费型,依赖单阶段: thenAccept()thenAcceptAsync()
    1. CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "hello")
    2. .thenAcceptAsync(a -> {
    3. a = a + " lucy !";
    4. log.info("ret ======> {}", a);
    5. });
    6. log.info(" ======== end ========================");
    7. // 执行结果:ret ======> hello lucy ! 而且是异步的,不会阻塞主线程,下面的end是先打印出来的
    1. 消费型,依赖两个任务都完成:thenAcceptBoth()thenAcceptBothAsync()
    1. CompletableFuture.supplyAsync(() -> "hello")
    2. .thenAcceptBoth(CompletableFuture.supplyAsync(() -> " lili"), (a, b) -> {
    3. try {
    4. TimeUnit.SECONDS.sleep(3);
    5. } catch (InterruptedException e) {
    6. e.printStackTrace();
    7. }
    8. log.info("=======>{}", a + b);
    9. });
    10. // 执行结果:=======>hello lili
    1. 消费型:acceptEither() 依赖两个任务中先执行结束的那个
    1. CompletableFuture.supplyAsync(() -> {
    2. try {
    3. TimeUnit.SECONDS.sleep(3);
    4. } catch (InterruptedException e) {
    5. e.printStackTrace();
    6. }
    7. return "lucy";
    8. }).acceptEither(CompletableFuture.supplyAsync(() -> "lili"), a -> {
    9. log.info("hello {}", a);
    10. });
    11. // 执行结果:hello lili
    1. 消费型,无论正常,还是异常都会消费处理,而且不会吞掉异常 whenComplete()whenCompleteAsync()
    1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    2. if (ThreadLocalRandom.current().nextInt(2) < 2) {
    3. throw new RuntimeException("error");
    4. }
    5. return "hello";
    6. }).whenComplete((a, e) -> {
    7. log.info("ret -> {}", a + " lili!");
    8. log.error("error", e);
    9. });
    10. log.info("future.get()-->{}", future.get());
    11. // 执行结果:ret -> null lili! 而且打印两次错误日志,一次是log打印,一次是get的时候。
    1. 产出型,无论正常还是异常都是处理,并返回结果。handlehandleAsync
    1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello")
    2. .handle((a, e) -> a + " lili!");
    3. log.info("ret ==> {}", future.get());
    4. // 执行结果:ret ==> hello lili!
    1. 产出型,异常时候进行处理,并产出,有点像try-catch(),exceptionally()
    1. CompletableFuture<Object> f =
    2. CompletableFuture.supplyAsync(() -> "Hello")
    3. .thenApplyAsync(res -> res + " World")
    4. .thenApplyAsync(
    5. res -> {
    6. throw new RuntimeException(" test has error");
    7. // return res + "!";
    8. })
    9. .exceptionally(
    10. e -> {
    11. log.error("exceptionally exception",e);
    12. return "出异常了。。";
    13. });
    14. log.info("ret ====> {}", f.get());
    15. // 执行结果:ret ====> 出异常了。。
    16. // 假如不抛出异常,执行结果:ret ====> Hello World!
    1. 无关性任务,互相依赖,allOf
    1. CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> "hello");
    2. CompletableFuture<String> f4 = CompletableFuture.supplyAsync(() -> "world");
    3. CompletableFuture<String> f5 =
    4. CompletableFuture.supplyAsync(
    5. () -> {
    6. try {
    7. TimeUnit.SECONDS.sleep(3);
    8. } catch (InterruptedException e) {
    9. e.printStackTrace();
    10. }
    11. return "!";
    12. });
    13. // 使用allOf方法 f3 f4 f5 都执行结束之前一直阻塞
    14. CompletableFuture.allOf(f3, f4, f5).join();
    15. System.out.println(f3.get());
    16. System.out.println(f4.get());
    17. System.out.println(f5.get());
    18. List<String> r =
    19. Stream.of(f3, f4, f5).map(CompletableFuture::join).collect(Collectors.toList());
    20. System.out.println(r);
    21. // 执行结果:hello
    22. // world
    23. // !
    24. // [hello, world, !]
    25. // 而且要等f1,f2,f3 三个任务都结束,不然会一直阻塞。

    这个类中的大部分方法上面都做了介绍,下面可以结合具体场景做一次演示。

三:DEMO

​ 场景1:需要查询一个订单信息,首先需要查询商品信息,然后查询支付信息,最后汇总成一个对象返回。

  1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "商品信息")
  2. .thenCombineAsync(CompletableFuture.supplyAsync(() -> "支付信息"), (a, b) -> {
  3. // 组装信息
  4. return a + b;
  5. });
  6. log.info("ret =========>{}",future.get());

​ 场景2:用户注册,首先需要校验用户信息,然后生成账号信息,最后保存到数据库。这三个操作互相依赖。

  1. // A -> B-> C
  2. CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
  3. if (ThreadLocalRandom.current().nextBoolean()){
  4. return;
  5. }
  6. throw new RuntimeException("该手机号码已经注册");
  7. }).thenCompose(ret -> CompletableFuture.supplyAsync(() -> {
  8. if (ThreadLocalRandom.current().nextBoolean()) {
  9. // 生成账号信息
  10. return "账号信息: 16289";
  11. }
  12. throw new RuntimeException("账号信息生成失败。。");
  13. })).thenApplyAsync(ret -> {
  14. // 保存账号信息
  15. log.info("保存账号信息->{}", ret);
  16. return "注册成功";
  17. }).exceptionally(e -> "注册失败" + e.getMessage());
  18. log.info("最终返回结果:===》 {}",future.get());

CompleteFuture实现简单的任务编排实践的更多相关文章

  1. 测试环境docker化—容器集群编排实践

    本文来自网易云社区 作者:孙婷婷 背景 在前文<测试环境docker化-基于ndp部署模式的docker基础镜像制作>中已经详述了docker镜像制作及模块部署的过程,按照上述做法已可以搭 ...

  2. 【须弥SUMERU】分布式安全服务编排实践

    一.概要 1.分布式安全服务编排概念 2.须弥(Sumeru)关键实现思路 3.应用场景 二.前言 在笔者看来,安全防御的本质之一是增加攻击者的攻击成本,尤其是时间成本.那么从防御的角度来说,如何尽早 ...

  3. 【阿里云产品公测】OTS使用之简单线上产品实践基于PythonSDK

    阿里云用户:morenocjm 实践是检验真理的唯一标准,学习技术需要通过实践过程中的不断尝试,才能够快速掌握要领.OTS是构建在阿里云飞天分布式系统之上的NoSQL数据库服务,提供海量结构化数据的存 ...

  4. 一个简单的 vue.js 实践教程

    https://segmentfault.com/a/1190000006776243?utm_source=tuicool&utm_medium=referral 感觉需要改善的地方有: ( ...

  5. 使用require.js和backbone实现简单单页应用实践

    前言 最近的任务是重做公司的触屏版,于是再园子里各种逛,想找个合适的框架做成Web App.看到了叶大(http://www.cnblogs.com/yexiaochai/)对backbone的描述和 ...

  6. Jenkins Jfrog Artifactory 以及docker下的pipeline 容器编排实践

    1. 测试环境情况: Docker主机 10.24.101.99 JFrog Artifactory 主机 (admin password) jenkinx github原始地址:https://gi ...

  7. CentOS6.5下docker的安装及遇到的问题和简单使用(已实践)

    转载自 CentOS6下docker的安装和使用 Docker是一个开源的应用容器引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.利用Linux的LXC.AUFS. Go语言.c ...

  8. 信息安全系统设计基础课程实践:简单TUI游戏设计

    简单TUI游戏设计                目       录               一                      Curses库简介与基本开发方法             ...

  9. Docker | 第七章:Docker Compose服务编排介绍及使用

    前言 前面章节,我们学习了如何构建自己的镜像文件,如何保存自己的镜像文件.大多都是一个镜像启动.当一个系统需要多个子系统进行配合时,若每个子系统也就是镜像需要一个个手动启动和停止的话,那估计实施人员也 ...

随机推荐

  1. 论如何在服务器上部署一个自己的web前端项目

    就在前两天,有新人通过邮箱问到笔者,如何部署自己的web前端项目?笔者在此详细介绍. 一.购买云服务器 配置用户名密码.安全组 二.下载Xshell于Xftp工具 用于登录服务器和文件上传 三.在li ...

  2. Python学习笔记摘要(一)类型 字符串 函数 列表 深浅拷贝

    python中的对象和类型 在python中,认为系统中的每一个"东西"都是一个对象,在python中,"对象"有着特殊的意义,python中的对象有: 一个标 ...

  3. GIMP 一键均匀添加多条参考线 一键均匀切分图片

    添加参考线 #!/usr/bin/env python2 # -*- coding: utf-8 -*- from gimpfu import * # orientation: ORIENTATION ...

  4. Python脚本导出AWS EC2资源清单

    环境需求 单位现在每隔一段时间需要核对一下 AWS 正在运行的 EC2 资源清单,为了避免核对失误以及重复性的工作,打算用脚本来解决这一重复性的工作.大概思路为 通过 AWS AK.SK 来索取 AW ...

  5. 尚硅谷 Go语言核心编程资料

    链接:https://pan.baidu.com/s/1zn8Jf82lxg-2msVS1Iedeg  提取码:5vsg  复制这段内容后打开百度网盘手机App,操作更方便哦

  6. 在C#中将图像转换为BASE64

    本教程说明如何在C#.NET Windows Forms Application中将图像转换为base64字符串,以及将base64字符串转换为图像.您可以创建一个新的Windows窗体应用程序项目来 ...

  7. tomcat快速发布备份脚本

    一.说明 我们每次在tomcat中发布新war包,总是要经历[备份-停机-上传-启动]这几个部分,其中上传的环节和网速有极大相关性,要是网速很慢,那么整个发布的时间就会很长. 如果我们不借助于自动化发 ...

  8. Linux的基础命令(一)

    目录: 一.Linux系统基础 1.shell      2. Linux命令的分类 二.Linux命令行 1.Linux命令行提示符      2.Linux通用命令行使用格式      3.Lin ...

  9. Oracle体系结构二

  10. java中各个类相互调用资源的原理

       当我们要进行跨类的调用/使用的时候,比如当前类调用另一个类中的变量或方法时, 这时需要一定的条件,如果那些将要被调用的变量或方法是static(静态)变量,也叫类变 量,那么可以通过类名调用,相 ...