案例详解
电商app中,商品详情页,开发一个接口提供以下信息
- 商品基本信息(名称、价格、库存等)
- 商品图片列表
- 商品描述信息
数据库中我们用了3张表存储上面的信息
- 商品基本信息表:t_goods(字段:id、名称、价格、库存等)
- 商品图片信息表:t_goods_imgs(字段:id、goods_id、图片路径等)
- 商品描述信息表:t_goods_ext(字段:id、goods_id、描述信息等)
常规写法,伪代码如下:
public Map<String,Object> detail(long goodsId) {
//创建一个map
Map<String,Object> map = new HashMap<>();
//step1:查询商品基本信息,放入map
map.put("goodsModel",(select * from t_goods where id = #goodsId#));
//step2:查询商品图片列表,返回一个集合放入map
map.put("goodsImgsModelList",(select * from t_goods_imgs where goods_id = #goodsId#));
//step3:查询商品描述信息,放入map
map.put("goodsExtModel",(select * from t_goods_ext where goods_id = #goodsId#));
return map;
}
这种写法很简单,假设上面每个步骤耗时
500ms
,此接口总耗时
>=1500ms
,其它涉及到网络传输耗时,估计总共在
1600ms
左右
我们看一下上面的逻辑,整个过程是按照顺序执行的,实际上3个查询之间是没有任何依赖关系的,所以说,3个查询可以同时执行
使用多线程对代码进行重构:
package thread.demo;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
* Created by weiliangchun on 2019/11/28
*/
public class Demo1 {
/**
* 获取商品基本信息
* @param goodsId
* @return 商品基本信息
* @throws InterruptedException
*/
public String goodsDetailModel(long goodsId) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
return "商品id:" + goodsId + ",商品基本信息.....";
}
/**
* 获取商品图片列表
* @param goodsId
* @return
* @throws InterruptedException
*/
public List<String> goodsImgsModelList(long goodsId) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
return Arrays.asList("图1", "图2", "图3");
}
/**
* 获取商品描述信息
* @param goodsId
* @return
*/
public String goodsExtModel(long goodsId) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
return "商品id:" + goodsId + ",商品描述信息.....";
}
//创建个线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
public Map<String, Object> goodsDetail(long goodsId) throws ExecutionException, InterruptedException {
Map<String, Object> result = new HashMap<>();
//异步获取商品基本信息
Future<String> goodsDetailModelFuture = executorService.submit(() -> goodsDetailModel(goodsId));
//异步获取商品图片列表
Future<List<String>> goodsImgsModelListFuture = executorService.submit(()->goodsImgsModelList(goodsId));
//异步获取商品描述信息
Future<String> goodsExtModelFuture = executorService.submit(() -> goodsExtModel(goodsId));
result.put("goodsDetailModel", goodsDetailModelFuture.get());
result.put("goodsImgsModelList", goodsImgsModelListFuture.get());
result.put("goodsExtModel", goodsExtModelFuture.get());
executorService.shutdown();
return result;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
Map<String, Object> map = new Demo1().goodsDetail(1L);
System.out.println(map);
System.out.println("耗时(ms):" + (System.currentTimeMillis() - startTime));
}
}
输出
{goodsDetailModel=商品id:1,商品基本信息....., goodsImgsModelList=[图1, 图2, 图3], goodsExtModel=商品id:1,商品描述信息.....}
耗时(ms):639
可以看出耗时700毫秒左右,性能提升了2倍,假如这个接口中还存在其他无依赖的操作,性能提升将更加显著,上面使用了线程池并行去执行3次查询的任务,最后通过
Future
获取异步执行结果。
整个优化过程:
- 先列出无依赖的一些操作
- 将这些操作改为并行的方式
用到的技术有:
- 线程池相关知识
-
Executors
、
Future
相关知识
总结
对于无依赖的操作尽量采用并行方式去执行,可以很好的提升接口的性能
版权声明:本文为w139074301原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。