CompletableFuture、EasyExcel、PageInfo

CompletableFuture(redis中key的过期时间设置的是一个小时)

  • 通过内部的性能监控工具进行测试发现,优化前的请求耗时为300毫秒左右,优化后降为了100毫秒。吞吐量tps是2000。

  • CompletableFuture 是 Java8 新增的一个支持非阻塞的,用于异步编程来编写非阻塞的代码,使任务运行在一个单独的线程中,与主线程隔离,在这种方式中,主线程不会被阻塞,不需要一直等待子线程完成,从而使主线程可以并行的执行其他任务,让我们把耗时的操作从我们本身的调用线程中释放了出来,就好像我们去饭店吃饭,不需要我们自己去煮饭,我们点餐后就可以继续干自己的事,然后餐厅煮好了就回调我开始吃饭。

  • CompletableFuture 实现了 Future 和 CompletionStage接口,并且提供了许多关于创建,链式调用和组合多个 Future 的便利方法集,而且有比较好的异常处理支持。

  • CompletableFuture.supplyAsync() (舍pe耐 额think)。它内部有一个 asyncSupplyStage 方法(它是并行执行的),如果没有给它传入 executor(以可摘cute)执行者,它就会使用 ForkJoinPool.commonPool() 作为它的线程池 执行异步代码。

  • CompletableFuture用的是默认的线程池,在处理过程中我询问了负责人,他们给的答案是这里采用默认的即可,因为两者都可以实现目的。之所以没有复用项目中已有的线程池,是因为我们的线程池根据业务进行了隔离,不同的业务公用一个线程池的话,如果某个业务执行的很慢,就会影响其他业务了,所以不同的业务拥有自己独立的线程池。

  • runAsync方法不支持返回值。supplyAsync可以支持返回值。

  • 传入参数是协议参数和skuId的set集合,通过四个不同的查询接口去主站中查找对应数据,查到后进行组合,得到的是一个key为skuId,value为sku详情的map。组合过程是通过skuId来从四个数据中获取sku详情所需的字段,中间会经历一些业务所需格式的转换和组合。

  • 如果异步过程中需要用到前面的返回结果,可以通过 CompletableFuture 的 thenCompose 方法来实现,它可以对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> f = CompletableFuture.supplyAsync(() -> {
            int t = 3;
            System.out.println("t1=" + t);
            return t;
        }).thenCompose(param -> CompletableFuture.supplyAsync(() -> {
            int t = param * 2;
            System.out.println("t2=" + t);
            return t;
        }));
        System.out.println("thenCompose result : " + f.get());
    }
}

返回结果是 t1=3,t2=6,thenCompose result :6

说辞

  • 在从京东的主数据商品池查找商品的基本信息、大字段信息、图片信息和扩展信息时,我最开始使用的是简单的查询逻辑进行的查找,整体是一个按顺序串行执行的过程。
  • 很显然,查询完这四种数据所花费的时间是分别查询他们的时间总和。于是我改进了这个方案,整体改进逻辑是将串行的执行的过程优化为并行的执行过程。
  • 实现的方法是,采用了Java8的CompletableFuture方法,它提供了一个异步运算结果的建模,让我们把耗时的操作从本身的调用线程中释放出来,只需要完成后进行回调即可,就好像我们去饭店吃饭,不需要我们自己去煮饭,我们点餐后就可以继续干自己的事,然后餐厅煮好了就回调我开始吃饭。
  • 通过这个改进,查询完这四种数据所花费的时间就是这四个查询中耗时最长的那个。相比优化前,降低了整体耗时。通过内部的性能监控工具进行测试发现,优化前的请求耗时为300毫秒左右,优化后降为了100毫秒。吞吐量tps是2000。
  • 我通过编写测试用例进行了测试。测试代码的编写逻辑大致是创建一个线程,调用优化前的这个查询接口,输出查询所耗时长。
    /**
     * 查询渠道商品(包含基本信息、图片、大字段、扩展信息、装吧) 目前提供给jos
     */
    public Map<Long, SkuDetailDto> queryProductDetail(CrsDto crsDto, Integer pureSkuMark) {
        Protocol protocol = getProtocol();
        CompletableFuture<Map<Long, SkuBaseInfoDto>> skuBaseInfosFuture =
                CompletableFuture.supplyAsync(() -> productRpcWrap.querySku(protocol, crsDto));
        CompletableFuture<Map<Long, SkuBigFieldInfoDto>> skuBigFieldsFuture =
                CompletableFuture.supplyAsync(() -> assemblyRpcWrap.queryProductBigFieldBySku(protocol, crsDto));
        CompletableFuture<Map<Long, List<ImageDto>>> skuImagesFuture =
                CompletableFuture.supplyAsync(() -> materialRpcWrap.queryImage(protocol, crsDto));
        CompletableFuture<Map<String, AttributeSettingResult>> skuSpecificationExtAttrsFuture =
                CompletableFuture.supplyAsync(() -> materialRpcWrap.queryNewAttributeSettingForAssembly(protocol, crsDto));

        Map<Long, SkuBaseInfoDto> skuBaseInfos = null;
        Map<Long, SkuBigFieldInfoDto> skuBigFields = null;
        Map<Long, List<ImageDto>> skuImages = null;
        Map<String, AttributeSettingResult> skuSpecificationExtAttrs = null;

        try {
            skuBaseInfos = skuBaseInfosFuture.get();
            skuBigFields = skuBigFieldsFuture.get();
            skuImages = skuImagesFuture.get();
            skuSpecificationExtAttrs = skuSpecificationExtAttrsFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            log.error("查询渠道商品信息异常,skuIds={}", crsDto.getSkuIds(), e);
            throw new RuntimeException("查询渠道商品信息异常!");
        }

        return constructSkuBaseInfo(skuBaseInfos, skuBigFields, skuImages, skuSpecificationExtAttrs,pureSkuMark);

EasyExcel

  • 可以通过 @ExcelProperty(“客户Id”) 注解来指定每个字段的列名称,以及下标位置。
    @RequestMapping("/exportData")
    @ResponseBody
    public Result export(ProductInfoExtVo productInfoExtVo) {
        QueryProductExt queryProductExt = getQueryProductExt(productInfoExtVo);
        String fileName = "/export/Data/" + System.currentTimeMillis() + ".xlsx";
        File file = new File(fileName);
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(fileName, ProductExtDetailShow.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("ProductExtDetail").build();
            int i = 1;
            PageInfo<ProductExt> page;
            do {
                page = PageUtils.page(i, 1000, () -> productExtMapper.getProductInfoExt(queryProductExt));
                List<ProductExtDetail> productExtDetail = getProductExtDetails(page.getList());
                List<ProductExtDetailShow> detailShow = getProductExtDetailShow(productExtDetail);
                excelWriter.write(detailShow, writeSheet);
                i++;
            } while (i <= page.getPages());
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
        Boolean aBoolean = ctpJssHelper.uploadFile2WareJss(file.getName(), file);
        if (!aBoolean) {
            throw new CtpException("上传文件到jss失败");
        }
        file.delete();
        return Result.createWithSuc(ctpJssHelper.getWareFileUrl(file.getName()).toString());
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值