completablefuture的使用 - 并发执行多个任务

302 阅读1分钟

需求描述

  1. 提供给前端一个接口,在接口中的逻辑是,为前端传递过来的git仓库增加分支
  2. 需求已经完成,但是接口处理速度过慢。因为每个git仓库增加分支都要远程调用gitlab的接口,但如果git仓库数量超过50个,那个整个耗时就会大于1分钟,超过前端超时控制,导致页面显示异常

需求分析

  1. 需要引入多线程,并发执行多个增加分支的操作
  2. 然后在主线程中等待多个任务执行完成,再继续后续如落库等操作
  3. 可以使用AbstractExecutorService.invokeAll 或者Completablefuture.allOf

具体实现

/**  
* 新建分支  
* @param branchName 分支名称  
* @param gitOperaList 仓库列表  
*/  
public void createNewBranch(String branchName, List<GitOpera> gitOperaList) {  
    if (StringUtils.isBlank(branchName)) {  
        throw new RuntimeException("分支名称必输");  
    }  
    if (CollectionUtils.isEmpty(gitOperaList)) {  
        throw new RuntimeException("提交信息必选");  
    }  
    // 把仓库列表封装转换为任务列表  
    // gitForkJoinPool 为定义定义好的工作窃取线程池  
    List<CompletableFuture<Void>> completableFutures = gitOperaList.stream()  
        .map(gitOpera -> CompletableFuture.runAsync(() -> {  
                if (StringUtils.isBlank(gitOpera.getCommitId())) {  
                    gitOpera.setBranchName("【失败】commitId为空");  
                } else {  
                    try {  
                        GitlabUtils.createBranch(branchName, gitOpera.getCommitId(), gitOpera.getGitUrl());  
                        gitOpera.setBranchName("【成功】" + branchName);  
                    } catch (Exception e) {  
                        log.error(e.getMessage());  
                        gitOpera.setBranchName("【失败】新建分支失败:" + e.getMessage());  
                    }  
                }  
                gitOpera.setId(null);  
                }, gitForkJoinPool))  
        .collect(Collectors.toList());  
    try {  
        // 批量执行任务,并阻塞所有等待任务执行完成  
        CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()])).get();  
    } catch (Exception e) {  
        throw new RuntimeException("多线程执行异常,请重新执行" + e.getMessage());  
    }  
    // 后续落库等操作  
    updateOrSaveListByUnion(gitOperaList);  
}

实现效果

使用多线程后,可以达到100个仓库,20秒内增加分支操作完成,前端不再超时异常