java8 CompletableFuture_异步执行多个任务

微笑、不失礼 提交于 2020-01-21 19:49:55

前言

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!