这是我参与8月更文挑战的第5天,活动详情查看: 8月更文挑战
说完线程池,就已此篇作为并发编程的结束篇。下面是我画的脑图,由于时间不够充裕可能会有一些错误和疏漏,还望见谅。原图的获取方式:并发编程
并发编程
回到那个问题:为什么需要并发?
我们渴求的是在性能遇到瓶颈的时候,通过多核CPU的优势让程序运行的更快。但是并发并不是总能改进性能,并发在CPU有很多空闲时间时能明显改进程序的性能,但当线程数量较多的时候,线程间频繁的调度切换反而会让系统的性能下降。这种情况很容易模拟,就测试一个循环,当你的数据量在百万以下时,可以发现并发执行的速度不一定比串行快多少。
而且你还将面临下面的问题:
- 编写并发程序会在代码上增加额外的开销
- 正确的并发是非常复杂的,即使对于很简单的问题
- 并发中的缺陷因为不易重现也不容易被发现
- 并发往往需要对设计策略从根本上进行修改
好在是Java为开发者提了很多好用的工具(感谢Doug Lea),并且还有很多开源框架生态的支持,而我们需要做的只是在合适的场景下使用合适的工具。但是我这里用“只是”这个词确实有点膨胀,因为很多场景是很难评估的,甚至会出现很诡异的错误。
如何评估
虽然评估是一种猜测,但是也不是瞎猜。大致可以从下面几个方向进行评估:
并发用户数 首先我们需要知道我们的功能面向的用户是哪些,比如互联网电商平台,那可能面向的用户有消费者、商户、运营、采销等等,很明显的是面向消费者的功能是最需要考虑并发场景的。
统计 其次,我们需要对我们的系统业务请求进行统计(日志、探针、大数据等),通常我们统计往期一个月和大促期间整体流量和峰值等数据。
压力测试 有了这些数据那对下次来说就是一种参考,根据这些参考值再乘以经验系数我们再进行系统性的压测。
资源冗余 你预估的不一定是准确的,就算是能准确预估,但是也逃不过一些特殊场景,比如微博吃瓜。
诡异的问题
有很多问题很难出现,但是到生产环境上就可能会遇到,而线上又不能调试代码,所以线上问题定位就只能看日志、系统状态和dump线程,本节只是简单地介绍一些问题处理的方式,以帮助大家定位线上问题。
发现问题
发现问题有很多种方式,如系统异常、告警、CPU飙升、频繁FULL GC、服务超时甚至是系统宕机等。
分析问题
有些问题很难分析,这就需要你掌握一些分析工具,如分析系统日志、分析head dump、javacore等。
问题复现
尽量在测试环境复现问题,这样对于解决问题来说是比较稳妥的,说明你已经掌握了问题的关键。但是也不一定能顺利复现问题,这种情况要更小心。(通常来说网络问题是最难复现的,遇过两次,好几天可以不干活了,光抓包分析了)
问题解决
这里不想多说,能分析出问题来,就能够解决,即使解决的并不优雅也没那么重要。
总结与输出文档
有些人解决完问题,就结束了。但是我想说的是文档非常重要,这是自我提升的最好体现,你解决了一个可能几年都不会遇到的问题,这就是经验的积累。
流控
流控可以从多个维度来进行,比如针对QPS,并发线程数,黑白名单,加权分级等等,最典型最直接的便是针对QPS和并发线程数的流控。当然,要进行流控,首先等有一个流控的阀值,这个阀值不是说拍拍脑袋就能够想出来,不同类型的应用,所面临的情况不一样,也没有一个统一的衡量标准,必须经过多轮的压力测试,才能够得出一个比较靠谱的数值。
最后想说的是,如果你有时间一定去看看java并发包的代码,Doug Lea的注释让你看起来不会有很大压力,而且很多类他也都提供了模板用法。