[java并发] java高并发系列 - 第27天:实战篇,接口性能提升几倍原来这么简单

原文链接:查看原文

感谢公众号“ 路人甲Java”的分享,如有冒犯,请联系删除,快去关注他吧
在这里插入图片描述

案例讲解

电商app都有用过吧,商品详情页,需要给他们提供一个接口获取商品相关信息:

  1. 商品基本信息(名称、价格、库存、会员价格等)
  2. 商品图片列表
  3. 商品描述信息

数据库中我们用了3张表存储上面的信息:

  1. 商品基本信息表:t_goods(字段:id【商品id】,名称、价格、库存、会员价格等)
  2. 商品图片信息表:t_goods_imgs(字段:id、goods_ids【商品id】、图片路径),一个商品会有多张图片
  3. 商品描述信息表:t_goods_ext(字段:id,goods_id【商品id】、商品描述信息【大字段】)

这需求对于大家来说很简单把,伪代码如下:

public Map<String,Object> detail(long goodsId){
	//创建一个map
	//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("goodsExeModel",(select * from t_goods_ext where goods_id= #goodsId#));
	return map;
}

上面这种写法应该很常见,代码很简单,假设上面每个步骤耗时200ms,此接口总共耗时 >= 600毫秒,其他还涉及到网络传输耗时,估计总共会在700ms左右,此接口有没有优化的空间,性能能够提升多少?我们一起来挑战一下。

再看一下上面的逻辑,整个过程是按顺序执行的,实际上3个查询之间没有任何依赖关系,所以说3个查询可以同时执行,那我们对这3个步骤采用多线程并行执行,看一下最后什么情况:

package aboutThread.Concurrent.Day27;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Demo1 {
    
    /**
     * 获取商品信息
     * 
     * @param goodId
     * @return
     * @throws InterruptedException
     */
    public String goodsDetailModel(long goodId) throws InterruptedException{
        //模拟耗时,休眠200ms
        TimeUnit.MILLISECONDS.sleep(200);
        return "商品id" + goodId + ",商品基本信息....";
    }

    /**
     * 获取商品图片列表
     * @param goodsId
     * @return
     * @throws InterruptedException
     */
    public List<String> goodsImgsModelList(long goodsId) throws InterruptedException{
        //模拟耗时,休眠200ms
        TimeUnit.MILLISECONDS.sleep(200);
        return Arrays.asList("图1","图2","图3");
    }

    public String goodsExtModel(long goodsId) throws InterruptedException{
        //模拟耗时,休眠200ms
        TimeUnit.MILLISECONDS.sleep(200);
        return "商品id: " + goodsId + ",商品描述信息.....";
    }

    //创建线程池
    ExecutorService executorService = Executors.newFixedThreadPool(10);


    public Map<String,Object> goodsDetail(long goodsId) throws InterruptedException,ExecutionException{
        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());
        return result;
    }
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long startTime = System.currentTimeMillis();
        Map<String,Object> map = new Demo1().goodsDetail(1L);
        System.out.println(map);
        System.out.println("耗时(ms):" + (System.currentTimeMillis() - startTime));
    }
}

输出:

{goodsDetailModel=商品id1,商品基本信息...., goodsImgsModelList=[图1, 图2, 图3], goodsExtModel=商品id: 1,商品描述信息.....}
耗时(ms):218

可以看出,耗时200毫秒左右,性能提升了2倍,假如这个接口中还存在其他无依赖的操作,性能提升更加限制,上面使用了线程池并去执行3次查询任务,最后通过Future获取异步执行结果。

整个优化过程:

  1. 先列出无依赖的一些操作
  2. 将这些操作改为并行的方式

用到的技术有:

  1. 线程池
  2. Executors、Future相关知识

总结

  1. 对于无依赖的操作尽量采用并行方式去执行,可以很好的提升接口的性能
  2. 大家可以在你们的系统中试试这种方法,感受一下效果,会让你感觉很爽

你可能感兴趣的:(Java,#,Java并发)