首页 > 其他分享 >CompletableFuture异步任务编排

CompletableFuture异步任务编排

时间:2022-11-24 22:32:11浏览次数:40  
标签:异步 System 编排 future CompletableFuture println 线程 out


业务场景:

查询详情页的逻辑比较多,有些数据还需要远程调用,必然要花费更多的时间。

1、获取SKU的基本信息 0.5s

2、获取SKU的图片信息 0.5s

3、获取SKU的促销信息 1s

4、获取SPU的所有销售属性 1s

5、获取SPU的详情 1.5s

假如商品详情页的每个查询,如果如上标注的时间才能完成,那么用户需要4.5秒的时间,才能够看到商品详情页面的内容,很显然是不能够接受的。

如果有多个线程同时完成这6步操作,也许仅仅1.5秒就能够完成。

4 5 需要1的返回结果。

completableFuture简单调用

1、简单调用

//测试异步任务
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main .... start");
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
}, pool);

System.out.println("main ... end");
}

CompletableFuture异步任务编排_返回结果

 

2、runAsync

没有返回结果的方法调用:

CompletableFuture异步任务编排_线程池_02

 

3、supplyAsync

有返回结果的方法调用:无论是否get操作,使用了改操作,就是阻塞式等待。

CompletableFuture异步任务编排_Thread_03

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool);
System.out.println(future.get());

 返回结果:

CompletableFuture异步任务编排_返回结果_04

 

可以理解为多线程同步调用。get方法为阻塞式等待。

完成时的回调方法

1、whenComplete

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool).whenComplete((result,exception)->{
System.out.println("继续上一个线程的执行结果,用同一个线程继续执行");
System.out.println("result="+result);
System.out.println("exception="+exception);
}).exceptionally(excep->{
return 10; //遭遇到异常的返回结果
});
System.out.println(future.get());
System.out.println("main ... end");

 执行结果:

CompletableFuture异步任务编排_线程池_05

如果,i=10/0的执行结果如下:

2、exceptionally

CompletableFuture异步任务编排_返回结果_06

总结:

使用whenComplete的回调方法,参数一:返回结果;参数二:异常。但是该方法无法修改返回结果。是执行当前任务的线程继续执行回调方法的任务。

whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。

方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行。(如果是使用相同的线程池,也可能会被同一个线程选中执行)

使用exceptionally,如果遭遇到异常,可以修改返回结果的值。

3、handle方法完成后的处理

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, pool).handle((result,exception)->{
if(result!=null){
return result;
}
if(exception!=null){
return 0;
}
return 0;
});

 执行结果:

CompletableFuture异步任务编排_返回结果_07

 

4、线程串行化方法

CompletableFuture异步任务编排_Thread_08

thenRunAsync:

不得到上一步的返回结果,直接异步执行任务。

CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, pool).thenRunAsync(()->{
System.out.println("哈哈");
},pool);

 注意:此时,i=10/0 肯定是抛出异常了,但是咱们抛出了异常,所以程序中断;

CompletableFuture异步任务编排_返回结果_09

 如果修改异常代码,i=10/2;

CompletableFuture异步任务编排_Thread_10

如果使用了thenRun,则是用该线程继续执行任务。

CompletableFuture异步任务编排_java_11

 

thenAcceptAsync:

CompletableFuture异步任务编排_Thread_12

 

 得到上一步的返回结果,但是新任务结果不返回。

 

CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool).thenAccept(res->{
System.out.println("res="+res);
});

 执行结果:

CompletableFuture异步任务编排_java_13

thenApplyAsync:

CompletableFuture异步任务编排_java_14

 

得到上一步的返回结果,并且返回新任务的结果。

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool).thenApplyAsync(res -> {
System.out.println("res=" + res);
return 8;
}, pool);
System.out.println("get===="+future.get());
System.out.println("main ... end");

 

 执行结果:

CompletableFuture异步任务编排_线程池_15

 

两个任务组合,都要完成

两个任务都完成以后,触发一个事件

thenCombine:

组合两个future,获取两个future的返回结果,并返回当前任务的返回值;

thenAcceptBoth:

组合两个future,获取两个future的返回结果,然后处理任务,没有返回值;

runAfterBoth:组合两个future,不需要获取future的返回结果,只需要两个future处理任务完成后,处理该任务。

CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程1的ID:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("线程1结束:返回结果为" + i);
return i;
}, pool);

CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程2的ID:" + Thread.currentThread().getId());
return "线程2结束";
}, pool);

//Async加上就是异步,到最后执行;不加就是约等于同步
future01.runAfterBothAsync(future02,()->{
System.out.println("runAfterBoth:"+"不要线程1和线程2的返回结果,新开一个独立线程运行,不是在线程池中");
});

 

CompletableFuture异步任务编排_线程池_16

future01.thenAcceptBothAsync(future02, (res1, res2) -> {
System.out.println("thenAcceptBothAsync:" + "会获取到线程1和线程2的返回结果,res1=" + res1 + ",res2=" + res2 + ",但是新任务不会返回!");
}, pool);

 

 

CompletableFuture异步任务编排_异步_17

 

CompletableFuture<Object> future = future01.thenCombineAsync(future02, (res1, res2) -> {
return res1+"----"+res2;
}, pool);
System.out.println(future.get().toString());
System.out.println("main ... end");

 执行结果:

CompletableFuture异步任务编排_java_18

 

两个任务组合,一个完成

当两个任务中,任意一个future任务完成的时候,执行该任务。

applyToEither:两个任务有一个任务执行完成,获取它的返回值,处理任务并有新的返回值。

acceptEither:两个任务有一个任务执行完成,获取它的返回值,处理任务,没有返回值。

runAfterEither:两个任务有一个任务执行完成,不需要获取它的返回值,处理任务,并且没有返回值。

 

多任务组合

allOf:等待所有任务完成

anyOf:只要有一个任务完成

CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
allOf.get();
System.out.println("main ... end");

 

CompletableFuture异步任务编排_线程池_19

执行结果:

CompletableFuture异步任务编排_Thread_20

如果不加线程池,主线程结束,其余线程也会结束掉。其余线程就不打印东西了。所以要想清楚的看到结果,将线程执行放入到线程池中。  

 

 

 

标签:异步,System,编排,future,CompletableFuture,println,线程,out
From: https://blog.51cto.com/u_15890333/5885136

相关文章

  • vue+element-ui异步加载树结构-前端(全)
    element-ui异步加载行政区划树功能:进入页面,左侧显示行政区划树的顶级目录,单击目录左侧的箭头,则向后端发送请求,获得该级目录的子目录;以此类推;点击目录本身,则向后端发请求和右......
  • jquery实现多个异步方法的同步调用
    js顺序执行两个异步方法需求场景:[由于某种影响,框架环境不能支持es6的promise语法]1、第一下拉框需要进行加载字典【已经封装好的方法1】异步2、加载完成字典之后才能赋值......
  • Java之支付宝(电脑网站支付)成功后 同步回调,异步回调验证签名报错解决思路
    摘要:在做支付宝电脑网站支付的接口时候(这里仅限使用支付宝官网提供的SDK接入支付宝支付接口),支付成功了,但是支付宝回调的时候老是报签名失败,经过查看资料,发现是支付宝公钥......
  • 微信小程序异步回调函数恶梦和解决办法
    问题先看看下面的代码,是读写取腾讯cos,因为几个对象间是有层次关系的,要读出一个取值然后作为另一个的条件,再去读,依次有几层关系。按照官方文档,每一次都要放在回调函数里取......
  • 关于配置执行定时任务和异步任务的线程池配置类
    packagecom.liftsail.rsademo.utils;importlombok.extern.slf4j.Slf4j;importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;importorg.springf......
  • 什么是容器编排及编排的优点
    容器化之后,以Docker为例,可以通过CLI(CommandLineInterface,命令行界面)来管理容器的生命周期,比如将容器提交到新镜像上、上传镜像到注册中心、终止运行中的容器、资源调度和......
  • 企业级mysql数据库集群实战—— MySQL主从复制之异步复制(传统复制Postion与Gtid)
    企业级mysql数据库集群实战(2)——MySQL主从复制之异步复制(传统复制Postion与Gtid)目录一. 主从复制简介   1、概念   2、原理   3、优点二......
  • Python爬虫如何实现多线程异步
    如果自己的电脑配置高操作系统可以多任务运行的,应该首先要考虑单核CPU是怎么执行多任务的,操作系统会让各个任务交替执行。例如:任务1执行0.02秒,切换到任务2,任务2执行0.02秒,再......
  • Node.js 异步程序运行结果及分析
    源程序见:https://www.cnblogs.com/fitmap/p/16915027.html运行结果:2022-11-23T02:14:04.688ZStartmain2022-11-23T02:14:04.690ZStartpromisemain2022-11-23T02:1......
  • 容器与容器编排系统
       Docker公司发明的「容器镜像」技术,创造性地解决了应用打包的难题。改变了一大批诸如容器编排、服务网格和云原生等技术,深刻影响了云计算领域的技术方向。一、Docke......