本文是关于多线程适用的业务场景的讨论。为了让文章更容易理解,请务必先阅读前文。文章结尾会提出代码示例,欢迎童鞋们参与讨论。共同学习进步。
在读完本文后如果自己系统设计到很多的接口调用即可以进行多线程优化,使之性能加速,提供系统响应速度。本文使用的多线程工具类,会以maven包方式提供下载。谢谢您的阅读。
一、为何要使用多线程,使用异步并行来替换同步阻塞编程
众所周知,提高应用系统的响应速度可以有两点,一点是代码尽可能精简优化,第二点是尽可能优化同步调用接口导致的耗时浪费。而本文就是对第二点进行优化,即利用多线程的编程模型,从而达到用异步并行来替换同步阻塞编程。
下文小编以一个业务场景入手,看如何优化系统。
业务背景:
某支付公司的支付决策功能, 什么是支付决策,就是从用户商品产品风控等各个维度来提用户决策出用户自己当前能使用的支付工具。该模块因为涉及到支付安全,所以内部集成了多达十多个远程服务的调用。十多个接口就算每个耗时100毫秒,只要任何一个接口抖动一下,就可能造成接口响应缓慢,从而影响用户体验。这么说可能没有体感,举一个例子,假如你正在使用支付宝购买一瓶饮料,当打开支付宝准备支付的时候,页面突然卡顿了1s,才弹出来,这个时候内心是不是崩溃的。
下面这种图是不是就很有体感了,为用户决策出这个图上的支付工具。看似简单其实极其复杂,涉及十多个系统交互。
二、阅读前先要了解的业务知识
1. 下文将要涉及的支付码
2. 下文将要涉及的系统模块
三、两种编程模型图展示
- 同步阻塞串行调用
耗时: 每个接口调用耗时之和
- 多线程并行调用
耗时: 最大耗时接口时长
四、业务场景模拟
1. 业务说明
- 根据商户号查询商户支持的支付工具 【余额支付、白条支付、银行卡支付】
- 根据产品码查询当前支付产品可用支付工具 【余额支付、银行卡支付】
- 获取商户和当前产品支付工具的交集 【余额支付、银行卡支付】
- 如果存在余额则查询账务系统 【查询】
- 如果存在银行卡则查询风控系统 【查询】
- 返回结果 【余额支付】
经过一些列操作,返回用户可用的支付工具只有余额支付。(真实情况更复杂,在这里只是简单举例)
2. 业务流程图
3. 说明
当前业务依赖的业务系统很多,大概有13个业务系统的查询,这种场景下如何根据上面的流程图一样串行调用,可能处理的时间会很长,如上图耗时: 1 + 2 + 3 + 4 + 5 = 15s。 想象一下如果用户打开支付工具点击支付,app经过了15s之后才给你一个反馈,是不是内心是崩溃的。接着看下文,提供优化方案
五、多线程使用示例
1. 改造后的流程图
通过多线程并行,如上图耗时我们可以将原来串行的(1 + 2 + 3 + 4 + 5 = 15s), 优化为(2 + 3 + 5 = 10s)
耗时是小编为了方便根据序号定义的,真实系统提升会更大。
- 改造前代码 VS 改造后代码
将通用的逻辑封装成线程任务,多线程执行。
- 耗时对比
耗时可以看出,几乎时间缩短了1倍,真实的情况可能会更好。
- 模拟接口
商户查询
产品模拟查询
账务查询线程
风控查询
六、线程池工具分享
尽管多线程编程非常好用,但是对于那些对多线程不了解的同学来说,不了解导致了不敢用。再次分享一篇多线程执行原理的文章,是小编之前写的。看完你就知道原理了。
Java核心线程池原理知道原理了,就敢用了,所谓知己知彼嘛。但是原生的多线程API,其实并不是很好用。在此小编将自己的工具分享给大家,大家可以研究使用。
- 对原生线程池进行包装增强
- 对无结果任务添加监听器
- 对有返回值任务添加监听器
- 自定义线程池日志健康
maven仓库地址(2020年4月27提供下载,因为文章写在前面所以要等两天才能下载到)
<code><
dependency
><
groupId
>com.hanframeworkgroupId
><
artifactId
>commong.kitartifactId
><
version
>1.0.0-RELEASEversion
>dependency
>/<code>
七、多线程一定快吗
多线程一定快吗? 从理论上来看,我们可以理解计算机CPU是一个人,一个人同一时刻只能做一件事,但是现在的计算机基本都是多核多线程的,所以多线程可以理解成多个人干活,那么多个人干活肯定比一个人干活快。
但是实际场景是这样吗? 当然不是。具体问题还要具体分析
- 对于计算密集型来说: 要进行大量的计算,消耗CPU资源。比如计算圆周率、对视频进行高清解码就算你是2核心,多个线程来工作,其实也不会提高效率。
- 对于IO密集型来说: CPU消耗很少,任务的大部分时间都在等待IO操作完成,1个线程在等待,那么另外一个线程就会占用CPU。所以能很大程度提高效率
那么我们分析我们的业务系统,是什么密集型? 发现我们的逻辑基本就是接口调用,大部分时间花费在等待接口响应的时间。那么可以理解就是IO密集型(网络通信也是IO哦),这种场景使用多线程是非常适合的。
八、什么场景下适用于多线程。
- IO密集型操作(大多数业务系统只要不是计算类型的业务,剩下其他的都是IO密集型,自己可以评估)
- IO操作是否具有依赖关系,eg: 调用B系统依赖A接口的处理结果,调用C系统依赖AB的接口处理结果。那么这种场景多线程其实没有什么用,相反会增加线程上下文切换的耗时。
- 业务系统很简单,只有1或者2个接口调用,耗时并不高,这种情况也没必须使用多线程,因为使用了多线程就要对多线程进行维护和监控。维护成本大与接口成本
总结:
IO密集型 && 前后IO交互无依赖 && 耗时接口调用大于2个。当满足这三个条件就开始考虑使用多线程优化系统吧