近期开发任务中,有一个需求是拉取其他多个的接口的数据存入到表单中; 并且多个接口之间并没有什么太大的关联性, 并且没有顺序要求, 考虑使用线程池去处理这样任务. 且由于数据量较大, 考虑使用callable线程去并发拉取数据, 获取数据后再进行处理
1. 线程池
1.1 引入线程池的目的
我们知道,创建和销毁线程是一件十分损耗内存资源的, 在一个应用程序中,如果需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而在Java开发体系中,内存资源是及其宝贵的,所以,我们就提出了线程池的概念. 更具体点的解释是Java中开辟出的一种管理线程的概念,这个概念叫做线程池,从概念以及应用场景中,我们可以看出,线程池的好处,就是可以 方便的管理线程,也可以减少内存的消耗。
1.2 四种常用的线程池
- CachedThreadPool: 可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于 耗时少,任务量大的情况。
- SecudleThreadPool: 周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
- SingleThreadPool: 只有一条线程来执行任务,适用于有顺序的任务的应用场景。
- FixedThreadPool: 定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程。
2. Callable线程和FutureTask组装数据
Callable是创建多线程的方式之一, 它可以有返回值,也可以抛出异常的特性;
FutureTask是一个可取消的异步计算。FutureTask提供了对Future的基本实现,可以调用方法去开始和取消一个计算,可以查询计算是否完成并且获取计算结果;
一个简单的demo展示:
FutureTask futureTask=new FutureTask(new Callable() {
@Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("calld方法执行了");
return "call方法返回值";
}
});
futureTask.run();
System.out.println("获取返回值: " + futureTask.get());
FutureTask futureTask1=new FutureTask(new Callable() {
@Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("calld方法执行了1");
return "call方法返回值1";
}
});
futureTask1.run();
System.out.println("获取返回值1: " + futureTask1.get());
在上述的需求当中,由于接口拉取数据是没有先后关系的, 我们可以单独去通过线程池创建多个callable线程, 并通过FutureTask获取异步线程拉取到的数据并组装数据.
3. 实战
ExecutorService executorService = Executors.newCachedThreadPool();
CompletionService<Map<String, String>> cs = new ExecutorCompletionService<>(executorService);
Callable compareCallable = () -> getCompareInfo(request);
Callable getDeptInfoCallable = () -> getDeptInfo(request);
Callable getPaymentDetailInfoCallable = () -> getPaymentDetailInfo(request);
Callable getAllowanceDetailCallable = () -> getAllowanceDetail(request);
//构建futureTask任务,控制返回顺序
FutureTask<Map<String, String>> futureTask1 = new FutureTask<Map<String, String>>(compareCallable);
FutureTask<Map<String, String>> futureTask2 = new FutureTask<Map<String, String>>(getDeptInfoCallable);
FutureTask<Map<String, String>> futureTask3 = new FutureTask<Map<String, String>>(getPaymentDetailInfoCallable);
FutureTask<Map<String, String>> futureTask4 = new FutureTask<Map<String, String>>(getAllowanceDetailCallable);
StopWatch sw = new StopWatch("差旅对账接口调用耗时");
sw.start("对比信息");
executorService.submit(futureTask1);
sw.stop();
sw.start("账单汇总");
executorService.submit(futureTask2);
sw.stop();
sw.start("账单明细");
executorService.submit(futureTask3);
sw.stop();
sw.start("差补明细");
executorService.submit(futureTask4);
sw.stop();
log.info("差旅对账接口调用耗时汇总" + sw.prettyPrint());
//获取对比信息
String compareResult = (futureTask1.get()).get("compareResult");
//获取差补行程信息
String orderSettlementDetailJson = (futureTask3.get()).get("orderSettlementDetailJson");
//获取补贴数据
String allowanceDetailJson = (futureTask4.get()).get("allowanceDetailJson");
Map<String, String> temp = futureTask2.get();
String allowanceSummaryRes = temp.get("allowanceSummaryRes");
String snapshotInfoRes = temp.get("snapshotInfoRes");