前言
CompletableFuture是java8提供的基于异步操作的封装,日常开发中怎能不用上一番呢。
1)聚合多个异步任务
需求:多个tab页包含不同的表格数据,并且带分页,页面首次加载时需要显示第一页数据,并且在tab顶上显示总量,如下图所示:
各个表格数据从es中查询,涉及到计算,此处可以让前端调用多个接口来组装数据,但考虑到查询效率和网络交互,采用后端以多线程的形式查询,组合多个结果返回给前端,后端实现如下:
//所有订单
CompletableFuture<OrdersBo.Item> allOrdersFuture = fillAllOrders(pd, ordersBo);
//及时量订单
CompletableFuture<OrdersBo.Item> inTimeOrdersFuture = fillInTimeOrders(pd, ordersBo);
//超时量订单
CompletableFuture<OrdersBo.Item> timeOutFuture = fillOverTimeOrders(pd, ordersBo);
//失败量
CompletableFuture<OrdersBo.Item> failOrderFutrue = fillFailOrders(pd, ordersBo);
//异常量
CompletableFuture<OrdersBo.Item> exceptionOrderFuture = fillExceptionOrders(pd, ordersBo);
//聚合几个查询的结果返回给前端
CompletableFuture.allOf(allOrdersFuture, inTimeOrdersFuture, failOrderFutrue, timeOutFuture, exceptionOrderFuture).join();
return ordersBo;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
上述其实就是用到了CompletableFuture的特性,CompletableFuture.allOf()方法需要其中的每个异步任务都结束,配合join实现阻塞的效果,类似的还有很多方法,可以在不同的场景下使用,比如anyOf,当面临多份数据来源时,选择最快的一方。
CompletableFuture提供的api方法很多,我们可以将其归类来理解,首先是以then开头的方法,如thenAccept
凡是带accept的方法都没有返回值,接收的是一个消费者(Customer)
accept和acceptAsync的区别是,带Async的方法,可以异步执行,默认是使用forkjoinpool并且可以指定其他线程池。
以apply结尾的参数是接收的一个生产者(FUNCTION),具有返回值。
以run开头的对先前的执行结果不关心,执行完毕后直接执行下一个操作。
带Either的用在两个异步方法,只要取其中一个执行完毕就执行操作。
2)配合spring的@Async使用
在演示程序里,我定义了两个方法,分别是请求百度和请求新浪,我希望让这两个请求再我自定义的线程池中执行。其中用到的spring-web中的restTemplate来做请求,在具体方法中打印出当前执行的线程(为线程取名是很重要的哦,特别是线上发生问题能很好的通过工具定位),主要代码如下
@Autowired
private RestTemplate restTemplate;
@Bean(name = "myExecutor")
public Executor buildExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("hyq线程前缀-");
executor.initialize();
return executor;
}
@Async("myExecutor")
public CompletableFuture<String> testBaidu(){
System.out.println("baidu : "+Thread.currentThread().getName());
ResponseEntity<String> result = restTemplate.getForEntity("https://www.baidu.com/", String.class);
String body = result.getBody();
return CompletableFuture.completedFuture(body);
}
@Async("myExecutor")
public CompletableFuture<String> testSina(){
System.out.println("sina: "+Thread.currentThread().getName());
ResponseEntity<String> result = restTemplate.getForEntity("https://www.sina.com.cn/", String.class);
String body = result.getBody();
return CompletableFuture.completedFuture(body);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
3)总结
CompletableFuture为我们封装了各种异步处理的特性,能有效的改善我们程序的性能,让我们能得心应手的实现各种复杂逻辑。
————————————————
版权声明:本文为CSDN博主「独行侠梦」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012811805/article/details/84843960
来源:CSDN
作者:BillowX_
链接:https://blog.csdn.net/weixin_35852328/article/details/104064504