使用CompletableFuture实现业务服务的异步调用-串行请求响应时间慢的优化思路

假如我有一个订单相关的统计接口,需要返回3样数据:今日订单数、今日交易额、总交易额。

一般的我们的做法是串行调用3个函数,把调用返回的结果返回给调用者,这3次调用时串行执行的,如果每个调用耗时1秒的话,3次调用总耗时就是3秒。

这种做法效率非常低,因为3次调用之间无所谓先后顺序,所以采用并行执行效率会更好。比如使用线程池ExecutorService实现异步调用。

其实Java8提供了一个非常牛逼的CompletableFuture类,也可以实现异步化:

package com.hisense.completableFuture.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class OrderService {

    /**
     * 今日订单数
     *
     * @return
     */
    public CompletableFuture<String> todayOrderCount() {
        return CompletableFuture.supplyAsync(
                () -> this.getTodayOrderCount()
        );
    }

    /**
     * 今日交易额
     * @return
     */
    public CompletableFuture<String> todayTurnover() {
        return CompletableFuture.supplyAsync(
                () -> this.getTodayTurnover()
        );
    }

    /**
     * 总交易额
     * @return
     */
    public CompletableFuture<String> totalTurnover() {
        return CompletableFuture.supplyAsync(
                () -> this.getTotalTurnover()
        );
    }

    /*==================================具体的业务场景处理逻辑====================================*/
    /**
     *  今日订单数
     * @return
     */
    private String getTodayOrderCount() {
        System.out.println(">>>>>>> 查询今日订单数:" + Thread.currentThread().getName());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "50";
    }

    /**
     * 今日交易额
     *
     * @return
     */
    private String getTodayTurnover() {
        System.out.println(">>>>>>> 查询今日交易额:" + Thread.currentThread().getName());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "200";
    }

    /**
     * 总交易额
     *
     * @return
     */
    private String getTotalTurnover() {
        System.out.println(">>>>>>> 查询总交易额:" + Thread.currentThread().getName());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "800";
    }
}
package com.hisense.completableFuture.controller;


import com.alibaba.fastjson.JSONObject;
import com.hisense.completableFuture.dto.OrderModel;
import com.hisense.completableFuture.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;

@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("/report")
    public JSONObject report() {
        long start = System.currentTimeMillis();
        JSONObject jsonObject = orderReport();
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        return jsonObject;
    }

    private JSONObject orderReport() {

        //OrderModel orderModel = new OrderModel();
        //注意下面json中设置的对象的值也可以放到orderModel中属性进行设置值;
        CompletableFuture<String> todayOrderCountFuture = orderService.todayOrderCount();
        CompletableFuture<String> todayTurnoverFuture = orderService.todayTurnover();
        CompletableFuture<String> totalTurnoverFuture = orderService.totalTurnover();

        JSONObject json = new JSONObject();


        todayOrderCountFuture.whenComplete((v, t) -> {

            json.put("todayOrderCountFuture", v);
        });
        todayTurnoverFuture.whenComplete((v, t) -> {

            json.put("todayTurnoverFuture", v);
        });
        totalTurnoverFuture.whenComplete((v, t) -> {

            json.put("totalTurnoverFuture", v);
        });

        CompletableFuture.allOf(todayOrderCountFuture, todayTurnoverFuture, totalTurnoverFuture)
                .thenRun(() -> System.out.println("完成!!!!"))
                .join();
        log.info("最后的执行结果: {}",json);
        return json;
    }
}

最后使用测试工具进行测试:

直接请求controller中对应的路径:

日志结果显示如下:

>>>>>>> 查询今日订单数:ForkJoinPool.commonPool-worker-1
>>>>>>> 查询今日交易额:ForkJoinPool.commonPool-worker-2
>>>>>>> 查询总交易额:ForkJoinPool.commonPool-worker-3
完成!!!!
2020-10-14 11:42:50.113  INFO 38776 --- [nio-9000-exec-2] c.h.c.controller.OrderController         : 最后的执行结果: {"todayTurnoverFuture":"200","totalTurnoverFuture":"800","todayOrderCountFuture":"50"}
耗时:1016

耗时时间只有1秒左右..

猜你喜欢

转载自blog.csdn.net/zty1317313805/article/details/109057858