CompleteFuture实现简单的任务编排实践
CompleteFuture实现简单的任务编排实践
一:前言
CompleteFuture是java8 新提供的API,是对函数式编程思想的体现,提供了很多的对于函数式编程支持。不止有同步处理功能,还有异步处理能力。
通过函数式编程可以实现线程的简单任务编排。高效,整洁实现多线程异步编程。
二:详细介绍
CompleteFuture 提供的API中以ansy结尾的都是异步处理的。
异步执行任务,并返回结果:
supplyAsync异步处理,并返回结果,默认使用ForkJoinPool.commonPool()线程池,同时提供支持自定义线程池的API。CompletableFuture.supplyAsync(() -> "HELLO");
// 自定义线程池
CompletableFuture.supplyAsync(()->"hello",ES);
- 异步执行任务,不返回结果:
runAsync
CompletableFuture.runAsync(() -> System.out.println("HELLO WORLD !"));
CompletableFuture.runAsync(() -> System.out.println("HELLO WORLD !"),ES);
- 依赖单一阶段:
thenApply thenApplyAsync
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "HELLO")
.thenApply(a ->
return a + " lili!";
});
- 组合与撰写:
thenCompose(),thenCombine(),thenCombineAsync.
CompletableFuture<String> f1 =
CompletableFuture.supplyAsync(() -> "hello")
.thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lili"))
.thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lucy"));
// 执行结果: =====> hello lili lucy
// mian线程下同步执行。
CompletableFuture<String> f1 =
CompletableFuture.supplyAsync(() -> "hello")
.thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lili"))
.thenCompose(res -> CompletableFuture.supplyAsync(() -> res + " lucy"))
.thenCombineAsync(CompletableFuture.supplyAsync(() -> " how are you!"), (a, b) -> a + b);
log.info("=====> {}", f1.get());
// 执行结果: =====> hello lili lucy how are you!
- 依赖两个任务中的一个:
applyToEither(),那个任务先结束,就依赖那个任务。
CompletableFuture<String> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
try {TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace();}
return "lucy";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
return "lili";
}), a -> "hello " + a);
log.info("ret ====> {}",voidCompletableFuture.get());
// 执行结果: ret ====> hello lili 如果下面sleep改成3s,执行结果:ret ====> hello lucy
- 消费型,依赖单阶段:
thenAccept(),thenAcceptAsync()
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "hello")
.thenAcceptAsync(a -> {
a = a + " lucy !";
log.info("ret ======> {}", a);
});
log.info(" ======== end ========================");
// 执行结果:ret ======> hello lucy ! 而且是异步的,不会阻塞主线程,下面的end是先打印出来的
- 消费型,依赖两个任务都完成:
thenAcceptBoth(),thenAcceptBothAsync()
CompletableFuture.supplyAsync(() -> "hello")
.thenAcceptBoth(CompletableFuture.supplyAsync(() -> " lili"), (a, b) -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("=======>{}", a + b);
});
// 执行结果:=======>hello lili
- 消费型:
acceptEither()依赖两个任务中先执行结束的那个
CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "lucy";
}).acceptEither(CompletableFuture.supplyAsync(() -> "lili"), a -> {
log.info("hello {}", a);
}); // 执行结果:hello lili
- 消费型,无论正常,还是异常都会消费处理,而且不会吞掉异常
whenComplete(),whenCompleteAsync()
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (ThreadLocalRandom.current().nextInt(2) < 2) {
throw new RuntimeException("error");
}
return "hello";
}).whenComplete((a, e) -> {
log.info("ret -> {}", a + " lili!");
log.error("error", e);
});
log.info("future.get()-->{}", future.get()); // 执行结果:ret -> null lili! 而且打印两次错误日志,一次是log打印,一次是get的时候。
- 产出型,无论正常还是异常都是处理,并返回结果。
handle,handleAsync
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello")
.handle((a, e) -> a + " lili!"); log.info("ret ==> {}", future.get()); // 执行结果:ret ==> hello lili!
- 产出型,异常时候进行处理,并产出,有点像try-catch(),
exceptionally()
CompletableFuture<Object> f =
CompletableFuture.supplyAsync(() -> "Hello")
.thenApplyAsync(res -> res + " World")
.thenApplyAsync(
res -> {
throw new RuntimeException(" test has error");
// return res + "!";
})
.exceptionally(
e -> {
log.error("exceptionally exception",e);
return "出异常了。。";
});
log.info("ret ====> {}", f.get()); // 执行结果:ret ====> 出异常了。。
// 假如不抛出异常,执行结果:ret ====> Hello World!
- 无关性任务,互相依赖,
allOf
CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<String> f4 = CompletableFuture.supplyAsync(() -> "world");
CompletableFuture<String> f5 =
CompletableFuture.supplyAsync(
() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "!";
}); // 使用allOf方法 f3 f4 f5 都执行结束之前一直阻塞
CompletableFuture.allOf(f3, f4, f5).join(); System.out.println(f3.get());
System.out.println(f4.get());
System.out.println(f5.get());
List<String> r =
Stream.of(f3, f4, f5).map(CompletableFuture::join).collect(Collectors.toList()); System.out.println(r); // 执行结果:hello
// world
// !
// [hello, world, !]
// 而且要等f1,f2,f3 三个任务都结束,不然会一直阻塞。
这个类中的大部分方法上面都做了介绍,下面可以结合具体场景做一次演示。
- 异步执行任务,不返回结果:
三:DEMO
场景1:需要查询一个订单信息,首先需要查询商品信息,然后查询支付信息,最后汇总成一个对象返回。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "商品信息")
.thenCombineAsync(CompletableFuture.supplyAsync(() -> "支付信息"), (a, b) -> {
// 组装信息
return a + b;
});
log.info("ret =========>{}",future.get());
场景2:用户注册,首先需要校验用户信息,然后生成账号信息,最后保存到数据库。这三个操作互相依赖。
// A -> B-> C
CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
if (ThreadLocalRandom.current().nextBoolean()){
return;
}
throw new RuntimeException("该手机号码已经注册");
}).thenCompose(ret -> CompletableFuture.supplyAsync(() -> {
if (ThreadLocalRandom.current().nextBoolean()) {
// 生成账号信息
return "账号信息: 16289";
}
throw new RuntimeException("账号信息生成失败。。");
})).thenApplyAsync(ret -> {
// 保存账号信息
log.info("保存账号信息->{}", ret);
return "注册成功";
}).exceptionally(e -> "注册失败" + e.getMessage());
log.info("最终返回结果:===》 {}",future.get());
CompleteFuture实现简单的任务编排实践的更多相关文章
- 测试环境docker化—容器集群编排实践
本文来自网易云社区 作者:孙婷婷 背景 在前文<测试环境docker化-基于ndp部署模式的docker基础镜像制作>中已经详述了docker镜像制作及模块部署的过程,按照上述做法已可以搭 ...
- 【须弥SUMERU】分布式安全服务编排实践
一.概要 1.分布式安全服务编排概念 2.须弥(Sumeru)关键实现思路 3.应用场景 二.前言 在笔者看来,安全防御的本质之一是增加攻击者的攻击成本,尤其是时间成本.那么从防御的角度来说,如何尽早 ...
- 【阿里云产品公测】OTS使用之简单线上产品实践基于PythonSDK
阿里云用户:morenocjm 实践是检验真理的唯一标准,学习技术需要通过实践过程中的不断尝试,才能够快速掌握要领.OTS是构建在阿里云飞天分布式系统之上的NoSQL数据库服务,提供海量结构化数据的存 ...
- 一个简单的 vue.js 实践教程
https://segmentfault.com/a/1190000006776243?utm_source=tuicool&utm_medium=referral 感觉需要改善的地方有: ( ...
- 使用require.js和backbone实现简单单页应用实践
前言 最近的任务是重做公司的触屏版,于是再园子里各种逛,想找个合适的框架做成Web App.看到了叶大(http://www.cnblogs.com/yexiaochai/)对backbone的描述和 ...
- Jenkins Jfrog Artifactory 以及docker下的pipeline 容器编排实践
1. 测试环境情况: Docker主机 10.24.101.99 JFrog Artifactory 主机 (admin password) jenkinx github原始地址:https://gi ...
- CentOS6.5下docker的安装及遇到的问题和简单使用(已实践)
转载自 CentOS6下docker的安装和使用 Docker是一个开源的应用容器引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.利用Linux的LXC.AUFS. Go语言.c ...
- 信息安全系统设计基础课程实践:简单TUI游戏设计
简单TUI游戏设计 目 录 一 Curses库简介与基本开发方法 ...
- Docker | 第七章:Docker Compose服务编排介绍及使用
前言 前面章节,我们学习了如何构建自己的镜像文件,如何保存自己的镜像文件.大多都是一个镜像启动.当一个系统需要多个子系统进行配合时,若每个子系统也就是镜像需要一个个手动启动和停止的话,那估计实施人员也 ...
随机推荐
- Python3-sqlalchemy-orm 分组统计
#-*-coding:utf-8-*- #__author__ = "logan.xu" import sqlalchemy from sqlalchemy import crea ...
- BeanUtils基本使用方法与原理
使用BeanUtils的原因 因为setProperty是JSP中的标签,因此使用model 2模式JSP+Servlet+JavaBean的时候,JSP将form提交给Servlet程序,而Serv ...
- 利用Struts2拦截器完成文件上传功能
Struts2的图片上传以及页面展示图片 在上次的CRUD基础上加上图片上传功能 (https://www.cnblogs.com/liuwenwu9527/p/11108611.html) 文件上传 ...
- CGLib 简析
背景 JDK 动态代理存在的一些问题: 调用效率低 JDK 通过反射实现动态代理调用,这意味着低下的调用效率: 每次调用 Method.invoke() 都会检查方法的可见性.校验参数是否匹配,过程涉 ...
- 跨 Docker 宿主机 macvlan 类型
跨 Docker 宿主机 macvlan 类型 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 三台 CentOS 7.0 虚拟机 (Vmware Workstation 15 ...
- 动态规划精讲(一)LC最长公共子序列
P1439 [模板]最长公共子序列 题目描述 给出1,2,-,n 的两个排列P1 和P2 ,求它们的最长公共子序列. 输入格式 第一行是一个数 n. 接下来两行,每行为 n 个数,为自然数 1,2 ...
- 洛谷P1781——宇宙总统(高精度排序)
题目描述 地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竟选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格式: 第一行为一个整数n,代表竞选 ...
- Android Studio找不到设备,解决adb占用问题的方法
使用as连接真机时,找不到设备,发现 D:\Android\Sdk\platform-tools\adb.exe start-server' failed -- run manually if nec ...
- Spring框架(第一天)
一. 引言 a) 什么是Spring框架?(spring官网:www.springsource.org) 3.x 不提供第三发依赖jar 目前已经到了5.x版本. Spring轻量级(代码入侵性小) ...
- 【死磕NIO】— 阻塞、非阻塞、同步、异步,傻傻分不清楚
万事从最基本的开始. 要想完全掌握 NIO,并不是掌握上面文章([死磕NIO]- NIO基础详解)中的三大组件就可以了,我们还需要掌握一些基本概念,如什么是 IO,5 种IO模型的区别,什么是阻塞&a ...