Java并行执行代码优化接口速度

        在优化接口速度过程中,有时避免不了SQL执行速度时间稍微慢的情况,而且如果存在多个SQL查询,整个接口执行的时间必然是这些查询时间之和+代码执行的时间;众所周知SQL查询的时间是比较长的,代码执行的速度还是非常快,本文章分享一个通过使用多线程并行的方式来优化接口速度。

这里有两段SQL查询

....

long start = System.currentTimeMillis();
// SQL查询1
List<Record> courseList = Db.find(Db.getSqlPara(sqlKey + "queryTeachingCourse", Kv.by("globalID", globalId + "%")));
long end = System.currentTimeMillis();
DSFLog.info(StrKit.format("查询结束,消耗时间:{}ms",end-start));

start = System.currentTimeMillis();
// SQL查询2
List<Record> teacherList = Db.find(Db.getSqlPara(sqlKey + "queryteachingcourseteacher", Kv.by("globalID", globalId + "%")));
end = System.currentTimeMillis();
DSFLog.info(StrKit.format("查询结束,消耗时间:{}ms",end-start));

...

 以上的两段查询执行顺序是先执行完①后再执行②,总查询时间 t = t1 + t2

从日志和浏览器控制台看得出此时的接口反应速度是非常慢的。


我们开始使用并行优化,对代码进行重构

① 申请3个线程 (最好是大于任务数一到两个,我这里是2个任务)

long start = System.currentTimeMillis();
// 申请3个线程 (最好是大于任务数一到两个,我这里是两个任务)
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletionService<TaskDto> executorCompletionService = new ExecutorCompletionService<TaskDto>(executor);

② TaskDto实体类

@Data
public class TaskDto {
    /**
     * 区分是哪个任务的唯一标记
     */
    private String key;
    /**
     * 任务需要返回的数据
     */
    private List<Record> data;
}

③ 创建并提交任务

// 并行任务①
Callable<TaskDto> courseListCallableTask = () -> {
    TaskDto courseListTaskDto = new TaskDto();
    List<Record> courseList = Db.find(Db.getSqlPara(sqlKey + "queryTeachingCourse", Kv.by("globalID", globalId + "%")));
    // 设置任务①的标识
    courseListTaskDto.setKey("courseList");
    courseListTaskDto.setData(courseList);
    return courseListTaskDto;
};
// 并行任务②
Callable<TaskDto> teacherListCallableTask = () -> {
    TaskDto teacherListTaskDto = new TaskDto();
    List<Record> teacherList = Db.find(Db.getSqlPara(sqlKey + "queryteachingcourseteacher", Kv.by("globalID", globalId + "%")));
    // 设置任务②的标识
    teacherListTaskDto.setKey("teacherList");
    teacherListTaskDto.setData(teacherList);
    return teacherListTaskDto;
};
//提交任务
executorCompletionService.submit(courseListCallableTask);
executorCompletionService.submit(teacherListCallableTask);

④ 取出任务执行结果

List<Record> courseList = new LinkedList<>();
List<Record> teacherList = new LinkedList<>();
try{
    // 有几个任务这里循环几次 得到每个任务的执行结果
    for (int i = 0; i < 2 ; i++) {
        // 这里的超时时间不要设置太长也不要太短,太短会导致任务没执行完就被取出结果导出抛空异常
        Future<TaskDto> poll = executorCompletionService.poll(1000, TimeUnit.MILLISECONDS);
        TaskDto taskDto = poll.get();
        // 取出唯一标识 将任务对应的结果装好
        if ("courseList".equals(taskDto.getKey())){
            courseList = taskDto.getData();
        }else{
            teacherList = taskDto.getData();
        }
    }
}catch (Exception e){
    // catch里写一份串行执行的代码 以防止并行执行异常导致整个接口报错
    DSFLog.error("并行查询异常,即将改为串行查询:"+e.getMessage());
    courseList = Db.find(Db.getSqlPara(sqlKey + "queryTeachingCourse", Kv.by("globalID", globalId + "%")));
    teacherList = Db.find(Db.getSqlPara(sqlKey + "queryteachingcourseteacher", Kv.by("globalID", globalId + "%")));
}
long end = System.currentTimeMillis();
DSFLog.info(StrKit.format("查询结束,消耗时间:{}ms",end-start));

优化结束!通过日志看一下代码执行情况

很明显,查询速度得到了很大提示,总查询时间 t = max(t1,t2)

在有更多个任务查询时,总查询时间也只是会是某个任务最大的查询时间t = max(t1,t2,t3,...),而不是所有任务查询时间之和t = t1+t2+t3+t...,从此看出任务数越多接口执行速度提升越大!

当然并行方法优化也有个场景无法使用,也就是查询①和查询②有关联的场景,比如需要拿查询①的结果作为参数才能进行查询②,从执行顺序的角度来看查询①和查询②就只能是串行,无法使用并行。

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值