有个需求调用了外部接口查询客户的违章信息,一共一千多辆车,查看日志的时候这段程序居然跑了有半个多小时。
之前的处理逻辑是将所有的数据遍历,根据客户的车辆信息一个个去调用接口。
这么长时间,肯定要优化。想了想:可以将查出来的所有数据分片,分n片,启动n个线程,分别去执行查接口的功能。由于公司使用的服务器一般四核cpu,所以使用可以将数据分成8片,并启动8个线程。(一个并发程序开多少线程合适?)
一、首先是启动8个线程,这里使用了JUC的线程池。
有一篇专门介绍创建线程池的方法:《Java ExecutorService四种线程池的例子与说明》
二、然后将数据分片
之前也专门写过一个文章,可以出门左拐,这里就不详细介绍了。 ==》List分片处理
三、处理数据
由于是单机程序,是将所有的数据查出来,然后分片处理,所以不会出现各种并发类型问题。但是还是有一个小小的问题,之前计算这段程序的处理时间失效了。原因是之前用主线程记录时间,程序也跑在主线程上,所以只需要在程序的前后new 两个时间,计算差值就可以了。现在使用子线程处理数据后,这样处理就不可以了。
之前处理运行时间的逻辑:
@RequestMapping("send-break-rules-msg")
public void sendMsgToClient() {
Date startDate = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.info("<<<<<<<<<<<<<<<send break rules msg start at:{}>>>>>>>>>>>>>>", sdf.format(startDate));
// 从数据库查数据
// ......
// 查询外部接口,处理数据
Date endDate = new Date();
log.info("<<<<<<<<<<<<<<<send break rules msg end at:{}>>>>>>>>>>>>>>", sdf.format(endDate));
log.info("<<<<<<<<<<<<<<<send break rules msg cost:{}>>>>>>>>>>>>>>", endDate.getTime() - startDate.getTime());
}
在主线程中使用CountDownLatch工具类,在每个子线程的处理逻辑最后加上 countDownLatch.countDown();
经过这样的处理之后,这段程序完美的别控制在了5分钟以内。