一、功能要求
业务方要求每天发一个统计日报到用户邮箱、业务为统计每日的多项市场指标数据,因为数据表中数据量庞大,每项指标的SQL是单独的逻辑,所以要在一个接口内执行多个SQL,所以查询接口响应很慢,大概需要30s左右。
二、需求分析
统计报表页面涉及到的统计指标数据比较多,每个指标需要单独的去查询统计数据库数据,单个指标的SQL执行只要3秒左右,但是页面的指标有n个,所以整体下来接口响应时间差不多半分钟。
三、解决方案
任务时间长是因为统计指标多,而且指标SQL是串行的方式去进行统计的,我们只需要考虑把这些指标从串行化的执行方式改成并行的执行方式,那么这个接口的响应时间可以缩短至接近某个SqL执行的时间, 让多个线程同步的执行任务,我们这里考虑使用多线程,每个指标查询SQL单独创建一个线程去执行,这样每个统计指标就可以并行的处理了。
四、具体实现
因为主线程需要每个线程的统计结果进行整合,然后同步返回给前端渲染,所以这里需要提供一种机制让主线程阻塞等待所有的子线程都执行完之后再对每个线程执行的返回结果进行整合。 这里我们使用CallAble+CountDownLatch +ThreadPool来完成此功能。
实现代码:
public class ThreadPoolCountDownLatch {
private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 6,
12, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20));
@Autowired
private UserService userService;
@Autowired
private IOrdersService iOrdersService;
public void doExecuteSql(){
CountDownLatch afTaskLatch = new CountDownLatch(2);
Future<List<Orders>> orderFuture=asyncTaskHandler(()->iOrdersService.list());
Future<List<User>> UserFuture=asyncTaskHandler(()->userService.list());
//...more
List<Orders> ordersList=fetchTaskResult(orderFuture,afTaskLatch);
List<User> userList=fetchTaskResult(UserFuture,afTaskLatch);
//..more
//阻塞主线程,等待所有工作线程执行完毕
try {
afTaskLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//执行任务,监听返回结果要用callable
private <T> Future<T> asyncTaskHandler(Callable<T> callable) {
try {
Future<T> future = threadPoolExecutor.submit(callable);
return future;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//获取执行结果
private <T> T fetchTaskResult(Future<T> future, CountDownLatch taskLatch) {
try {
return future.get();
} catch (Exception e) {
e.printStackTrace();
} finally {
taskLatch.countDown();
}
return null;
}
}
标签:指标,报表,SQL,ThreadPool,线程,CountDownLatch,执行,统计 From: https://www.cnblogs.com/zhengyixin/p/16623820.html