Java充电社
专辑
博文
联系我
本人继续续收门徒,亲手指导
Java高并发教程
-> 实战:你的接口太慢了需要优化
1、必须知道的几个概念
2、并发级别
3、有关并行的两个重要定律
4、JMM相关的一些概念
5、深入理解进程和线程
6、线程的基本操作
7、volatile与Java内存模型
8、线程组
9、用户线程和守护线程
10、线程安全和synchronized
11、中断线程的几种方式
12、JUC中ReentrantLock
13、JUC中的Condition
14、JUC中的LockSupport工具类
15、UC中的Semaphore(信号量)
16、JUC中的CountDownLatch
17、JUC中的循环栅栏CyclicBarrier
18、线程池
19、JUC中的Executor框架详解1
20、JUC中的Executor框架详解2
21、java中的CAS
22、java中的UnSafe类
23、JUC中的原子操作类
24、ThreadLocal、InheritableThreadLocal
25、JUC中的阻塞队列
26、JUC中一些常见的集合
27、实战:你的接口太慢了需要优化
28、实战:构建日志系统
29、实战:一起来搞懂限流
30、JUC中的CompletableFuture
31、等待线程完成的方式你知道几种?
32、原子操作增强类LongAdder、LongAccumulator
33、怎么演示公平锁和非公平锁
34、谷歌提供的一些好用的并发工具类
35、延迟队列 DelayQueue 详解
36、线程6种状态详解
37、如何实现一个通用的延迟队列?
上一篇:JUC中一些常见的集合
下一篇:实战:构建日志系统
<div style="display:none"></div> ## 电商接口案例讲解 电商app都有用过吧,商品详情页,需要给他们提供一个接口获取商品相关信息: 1. 商品基本信息(名称、价格、库存、会员价格等) 2. 商品图片列表 3. 商品描述信息(描述信息一般是由富文本编辑的大文本信息) 数据库中我们用了3张表存储上面的信息: 1. 商品基本信息表:t_goods(字段:id【商品id】、名称、价格、库存、会员价格等) 2. 商品图片信息表:t_goods_imgs(字段:id、goods_id【商品id】、图片路径),一个商品会有多张图片 3. 商品描述信息表:t_goods_ext(字段:id,goods_id【商品id】、商品描述信息【大字段】) 这需求对于大家来说很简单吧,伪代码如下: ```java public Map<String,Object> detail(long goodsId){ //创建一个map //step1:查询商品基本信息,放入map map.put("goodsModel",(select * from t_goods where id = #gooldsId#)); //step2:查询商品图片列表,返回一个集合放入map map.put("goodsImgsModelList",(select * from t_goods_imgs where goods_id = #gooldsId#)); //step3:查询商品描述信息,放入map map.put("goodsExtModel",(select * from t_goods_ext where goods_id = #gooldsId#)); return map; } ``` 上面这种写法应该很常见,代码很简单,假设上面每个步骤耗时200ms,此接口总共耗时>=600毫秒,其他还涉及到网络传输耗时,估计总共会在700ms左右,此接口有没有优化的空间,性能能够提升多少?我们一起来挑战一下。 在看一下上面的逻辑,整个过程是按顺序执行的,实际上3个查询之间是没有任何依赖关系,所以说3个查询可以同时执行,那我们对这3个步骤采用多线程并行执行,看一下最后什么情况,代码如下: ```java package com.itsoku.chat26; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.*; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo1 { /** * 获取商品基本信息 * * @param goodsId 商品id * @return 商品基本信息 * @throws InterruptedException */ public String goodsDetailModel(long goodsId) throws InterruptedException { //模拟耗时,休眠200ms TimeUnit.MILLISECONDS.sleep(200); return "商品id:" + goodsId + ",商品基本信息...."; } /** * 获取商品图片列表 * * @param goodsId 商品id * @return 商品图片列表 * @throws InterruptedException */ public List<String> goodsImgsModelList(long goodsId) throws InterruptedException { //模拟耗时,休眠200ms TimeUnit.MILLISECONDS.sleep(200); return Arrays.asList("图1", "图2", "图3"); } /** * 获取商品描述信息 * * @param goodsId 商品id * @return 商品描述信息 * @throws InterruptedException */ public String goodsExtModel(long goodsId) throws InterruptedException { //模拟耗时,休眠200ms TimeUnit.MILLISECONDS.sleep(200); return "商品id:" + goodsId + ",商品描述信息......"; } //创建个线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); /** * 获取商品详情 * * @param goodsId 商品id * @return * @throws ExecutionException * @throws InterruptedException */ public Map<String, Object> goodsDetail(long goodsId) throws ExecutionException, InterruptedException { Map<String, Object> result = new HashMap<>(); //异步获取商品基本信息 Future<String> gooldsDetailModelFuture = executorService.submit(() -> goodsDetailModel(goodsId)); //异步获取商品图片列表 Future<List<String>> goodsImgsModelListFuture = executorService.submit(() -> goodsImgsModelList(goodsId)); //异步获取商品描述信息 Future<String> goodsExtModelFuture = executorService.submit(() -> goodsExtModel(goodsId)); result.put("gooldsDetailModel", gooldsDetailModelFuture.get()); result.put("goodsImgsModelList", goodsImgsModelListFuture.get()); result.put("goodsExtModel", goodsExtModelFuture.get()); return result; } public static void main(String[] args) throws ExecutionException, InterruptedException { long starTime = System.currentTimeMillis(); Map<String, Object> map = new Demo1().goodsDetail(1L); System.out.println(map); System.out.println("耗时(ms):" + (System.currentTimeMillis() - starTime)); } } ``` 输出: ```java {goodsImgsModelList=[图1, 图2, 图3], gooldsDetailModel=商品id:1,商品基本信息...., goodsExtModel=商品id:1,商品描述信息......} 耗时(ms):208 ``` 可以看出耗时200毫秒左右,性能提升了2倍,假如这个接口中还存在其他无依赖的操作,性能提升将更加显著,上面使用了线程池并行去执行3次查询的任务,最后通过Future获取异步执行结果。 ## 整个优化过程 1. 先列出无依赖的一些操作 2. 将这些操作改为并行的方式 ## 用到的技术有 1. **<a target="_blank" href="/course/1/18">线程池相关知识</a>** 2. **<a target="_blank" href="/course/1/19">Executors、Future相关知识</a>** ## 总结 1. **对于无依赖的操作尽量采用并行方式去执行,可以很好的提升接口的性能** 2. 大家可以在你们的系统中试试这种方法,感受一下效果,会让你感觉很爽 <a style="display:none" target="_blank" href="https://mp.weixin.qq.com/s/_S1DD2JADnXvpexxaBwLLg" style="color:red; font-size:20px; font-weight:bold">继续收门徒,亲手带,月薪 4W 以下的可以来找我</a> ## 最新资料 1. <a href="https://mp.weixin.qq.com/s?__biz=MzkzOTI3Nzc0Mg==&mid=2247484964&idx=2&sn=c81bce2f26015ee0f9632ddc6c67df03&scene=21#wechat_redirect" target="_blank">尚硅谷 Java 学科全套教程(总 207.77GB)</a> 2. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484192&idx=1&sn=505f2faaa4cc911f553850667749bcbb&scene=21#wechat_redirect" target="_blank">2021 最新版 Java 微服务学习线路图 + 视频</a> 3. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484573&idx=1&sn=7f3d83892186c16c57bc0b99f03f1ffd&scene=21#wechat_redirect" target="_blank">阿里技术大佬整理的《Spring 学习笔记.pdf》</a> 4. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484544&idx=2&sn=c1dfe907cfaa5b9ae8e66fc247ccbe84&scene=21#wechat_redirect" target="_blank">阿里大佬的《MySQL 学习笔记高清.pdf》</a> 5. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485167&idx=1&sn=48d75c8e93e748235a3547f34921dfb7&scene=21#wechat_redirect" target="_blank">2021 版 java 高并发常见面试题汇总.pdf</a> 6. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485664&idx=1&sn=435f9f515a8f881642820d7790ad20ce&scene=21#wechat_redirect" target="_blank">Idea 快捷键大全.pdf</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/1/2883e86e-3eff-404a-8943-0066e5e2b454.png)
#custom-toc-container