使用多线程并行处理任务,提高效率

  • Post author:
  • Post category:其他




案例详解

电商app中,商品详情页,开发一个接口提供以下信息

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

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

  1. 商品基本信息表:t_goods(字段:id、名称、价格、库存等)
  2. 商品图片信息表:t_goods_imgs(字段:id、goods_id、图片路径等)
  3. 商品描述信息表: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

获取异步执行结果。

整个优化过程:

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

用到的技术有:

  1. 线程池相关知识

  2. Executors



    Future

    相关知识


总结

对于无依赖的操作尽量采用并行方式去执行,可以很好的提升接口的性能



版权声明:本文为w139074301原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。