大背景: 项目是一个 spring cloud 项目,其实这个无所谓,普通的 web 项目也是可以的,这里只是为了 方便模拟
先看一个常见的场景 , 一个controller 中调用了 其他系统的服务接口 代码如下:
其实就是 一个接口 ,发送了 两个 http 请求 ,然后将运行时间返回
性能分析, 线程是从上到下执行,两个方法 resultList 返回了 ,方法 ruleList 才能执行,这两个方法 是串行,这里考虑是不是 可以通过多线程 进行并行执行
使用 FutureTask 进行 异步 并行优化,优化之后的 时间 接近 两个http 中 请求时间较长的 时间,不在是 两个 http 时间之和
二 继续优化,使用线程池技术 进行再次优化
private ExecutorService executor = Executors.newFixedThreadPool(2); 创建一个线程池 ,里面又两个线程
代码 改为
executor.submit(getGroupResourceTask); 不再是 new Thread(getGroupResourceTask).start();
executor.submit(getGroupResourceTask);
三 继续优化, 最终优化结果如下,
@ResponseBody
@RequestMapping(value = "/getResourceGroupByType")
public Callable<Map<String, Object>> getResourceGroupByType() throws ExecutionException, InterruptedException {
long begin = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + "main:" + (begin));
Callable result = new Callable<Map<String, Object>>() {
@Override
public Map<String, Object> call() throws Exception {
System.out.println(Thread.currentThread().getName() + "Map:" + (begin));
long beginTimeq = System.currentTimeMillis();
Map<String, Object> m = new HashMap<String, Object>();
Callable getGroupResource = new Callable<List<TbResource>>() {
@Override
public List<TbResource> call() throws Exception {
return restTemplate.getForObject("http://resource/getGroupResource",List.class);
}
};
Callable getResourceByRule = new Callable<List<Integer>>() {
@Override
public List<Integer> call() throws Exception {
return restTemplate.getForObject("http://resource/getResourceByRule",List.class);
}
};
FutureTask getGroupResourceTask = new FutureTask(getGroupResource);
FutureTask getResourceByRuleTask = new FutureTask(getResourceByRule);
executor.submit(getGroupResourceTask);
executor.submit(getGroupResourceTask);
new Thread(getGroupResourceTask).start();
new Thread(getResourceByRuleTask).start();
m.put("code", StatusInfo.SUSSESS);
m.put("data", getGroupResourceTask.get());
m.put("existId", getResourceByRuleTask.get());
System.out.println(Thread.currentThread().getName() + "Map:" + (System.currentTimeMillis() -beginTimeq));
return m;
}
};
System.out.println(Thread.currentThread().getName() + "main:" + ((System.currentTimeMillis() -begin)));
return result;
}
重点 可以看到 主线程 基本上 1 毫秒就返回了结果,最终是 子线程 将结果返回
主线程基本不耗时间 就结束,意味着什么?
假如 我们现在的程序是 运行在 tomcat 上运行,tomcat 假设又 700 个线程,用现在这种方法,主线程 基本不耗时间 就结束,而 线程的吞吐量,其实就是靠 tomcat 的主线程,现在主线程基本上不耗时间,后面的瓶颈 其实就是 子线程的瓶颈,子线程 最后的瓶颈其实 就是 cpu
除去 Callable 方法 ,还可以使用 DeferredResult
private ExecutorService executorService = Executors.newFixedThreadPool(1);
正式开放中,一般使用 DeferredResult 这是线程可以自己控制的,使用线程池 来处理