java8_CompletableFuture_异步执行多个任务

2022-08-12 11:56:52
前言
  • CompletableFuture是java8提供的基于异步操作的封装,日常开发中怎能不用上一番呢。
1)聚合多个异步任务
  • 需求:多个tab页包含不同的表格数据,并且带分页,页面首次加载时需要显示第一页数据,并且在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;
  • 上述其实就是用到了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);
    }
3)总结
  • CompletableFuture为我们封装了各种异步处理的特性,能有效的改善我们程序的性能,让我们能得心应手的实现各种复杂逻辑。

  • 以上案例都已经push到
    侠梦的github 欢迎关注。

  • 作者:独行侠梦
  • 原文链接:https://blog.csdn.net/u012811805/article/details/84843960
    更新时间:2022-08-12 11:56:52