使用java线程进行异步处理

29 阅读2分钟

场景

公司有个报告导出的需求,但是报告导出的时间比较长,报告中查询的sql耗时较长,同时需要调用python脚本生成对应图片,过程长同时消耗的资源也比较大.
服务器使用的阿里云服务器,使用的域名也是阿里云的域名.
这样就会有个问题,阿里云的域名有个固定的限制,一个请求最长不能超过120秒,如果超过了120秒那么就会强制断开当前链接.

痛点: 由于强制断开的机制,请求报告的时候生成的过程时间耗时太长,经过测试一般情况下都在120秒以上,这还是在生成报告的时候使用了多线程的情况下,一开始没有使用多线程的情况,最长的时间有超过20分钟都没有生成对应报告的情况.

解决问题

解决思路: 前端首先调用一个接口,这个接口组装好参数,然后异步执行报告生成的代码,最后通过另外一个接口去获取当前报告的生成情况,异步调用的代码如下:

// 用于存储当前报告生成的状态
public static Map<String, ExportProjectCompleteVo> projectExportDoc = new HashMap<>();
public vo exportProjectComplete(Req req) {
    vo vo = new vo();
    String key = req.getProjectCode() + req.getStartDate() + req.getEndDate();
    // 当前生成过,直接取对应的报告地址
    if(ExportDocUtil.projectExportDoc.get(key) != null && ExportDocUtil.projectExportDoc.get(key).getWordPath() != null){
        // 当天已经生成过报告了,直接下载即可
        return ExportDocUtil.projectExportDoc.get(key);
    }
    vo.setKey(key);
    ExportDocUtil.projectExportDoc.put(key,vo);
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    // 异步执行 下载
    CompletableFuture.runAsync(() ->{
        asyncExportProjectComplete(req);
    },executorService);
    // 组装返回信息
    vo exportProjectComplete = new vo();
    exportProjectComplete.setKey(key);
    exportProjectComplete.setStatus(AsyncExportProjectEnum.START.getCode());
    return exportProjectComplete;
}

asyncExportProjectComplete(req); 就似乎报告生成的具体代码,当前的接口请求完后会马上返回,开启一个新的接口去执行 asyncExportProjectComplete(req) 的代码,在生成代码的方法里去维护 projectExportDoc Map 的信息,然后新开一个接口,让前端携带我们调用异步方法之前生成的 key 去请求另外一个接口.
另外一个接口就去拿 projectExportDoc 的状态即可