前言
学习多线程的根本目的是为了让程序能充分利用CPU资源在合理的时间范围内完成任务.现在的计算机往往是一个CPU多个物理核心,有的物理核心又可以模拟出两个逻辑核心,也就是所谓的超线程技术.不管是多线程还是超线程,目的只有一个: 提高计算能力.但是,任何事物有好的一面就有坏的一面,包括多线程.当我们享受着多线程带来的快感时,却不得不为各种复杂难懂的概念和难以复现的同步问题买单. 可这不就是我们的追求吗?用极致的性能应对极致的挑战.
在我看来,学习多线程的最大挑战有两个: 一个是编程模型的研究,另外一个是性能和同步问题的排查.我见过不止一个系统,由于性能问题实在太隐蔽,而且很难重现,所以最后只能定时重启一下server来解决.数据同步问题的根源在于JVM的内存模型. 我们知道,JVM的内存模型分为线程私有和线程共享两部分.当多个线程同时访问某一块共享内存时,就有可能出现各种各样怪异的问题,而且排查起来很痛苦.
术语
我们知道,解决数据同步问题的常规操作是加锁. 在正式讲解锁之前,我想先明确几组术语.只有我们对这些术语有着清晰一致的理解,才能更好的消化后面概念和原理,进而帮助我们建立清晰的知识体系.在多线程的语义下有这么几组概念:多线程与高并发,并行与并发,同步与锁.
多线程与高并发
高并发是我们要设计和实现的目标,而多线程是实现这一目标的方式或手段.实现高并发并非只有多线程这一种方式,还包括缓存,消息队列,分布式等等.
并发与并行
网上主流的文章都是这么说的: 当多个任务在一个CPU上交替执行是并发,在多个CPU上同时执行就是并行.这样并不能说错,但是会给人造成一种感觉,就是并发和并行的区别就在于CPU的个数.照这么理解的话,现在早已是单CPU多核或多CPU时代了,那应该没有并发程序了,可事实上真的是这样吗? 显然说不通!
那应该怎么理解呢? 并发和并行是两个维度,它们并不是非此即彼的关系,一个系统既可以是并发也可以是并行的.
并发
先说并发.举例来说:你开发了一个系统,它包含三个模块: 用户管理,产品管理和文章管理,而且整个开发过程中没有用到任何多线程技术(只有一个main线程). 现在有三个用户同时访问你的系统,第一个要修改自己的邮箱,第二个要删除一个产品,第三个要添加文章. 很显然,不管你的系统运行在几个CPU上,它都是支持并发访问的.因为我修改邮箱是不影响其他人删除产品和添加文章的.
在上面的例子中三个模块可以理解为三个任务.当然,如果你的系统足够复杂,每个模块还包括了很多子模块,那么子模块也可以理解为任务.所以并发是从任务的角度出发的,如果每个任务相互独立且可被同时访问那么我们就可以说它是支持并发访问的.具体这个同时是指在一个CPU上交替执行的"假同时"还是在不同CPU上并行运行的"真同时", 用户是不care的.
并行
那什么又是并行呢? 在我看来它一定要同时满足两个条件:一个任务可以被分解多个子任务,且每个子任务可由单独线程执行. 同样以上面的系统为例,在添加文章时,实际上分成三个子任务: 编辑文字,检查语法和上传图片. 主线程用来编辑文字,一个单独线程用来自动检查语法,还有一个线程用来上传图片.这三个子任务都完成才算添加完成.
所以并行是要求某一任务可被分解,而且子任务支持在不同线程中运行.
比较
通过上面的分析我们可以看出:
- 相同点: 它们都是面向任务,且不强调CPU的个数.其实关键还是看任务的实现,比如在一个单线程系统实现了5个任务,那么即使把它部署在10 CPU server上仍然无法实现并行. 因为系统本身无法把每个任务分配到单独的CPU上执行;
- 不同点: 并发的任务一般是兄弟关系,每个兄弟互不干扰.并行的任务是多是父子关系,每个子任务都可以运行在单独的线程. 如果讲到这里大家仍然不理解或者认为我说的不对,那我只能说见仁见智了.对于仍然认为跟CPU个数有关系的同学可以考虑这样一个问题:一个CPU执行两个任务和三个CPU执行五个任务有什么本质区别? 如果你能想到其实跟CPU个数没关系,还是要看任务的实现方式,那么咱们的思想就统一了.
同步和锁
最后一组概念是同步和锁.类似于多线程和高并发, 同步是一种数据保护机制,而锁是实现这种机制的常用方式.
总结
我们介绍了几组常用的术语,并重点分析了并行与并发的异同.大家可能有自己的理解,我也欢迎大家留言讨论,理不辨不明.
下一篇我们要讲解synchronized关键字.它是锁的一种重要实现. 其实网上关于synchronized的讲解已经非常多了,有些讲的也非常详细.那为什么在这里还要再讲一遍呢? 原因有二: 第一是本系列文章是讲解java多线程,而多线程离不开锁,所以不讲synchronized是不完整的.第二是对自己的总结.网上的文章写的再好,如果不能用自己的语言表达出来还是没有掌握.这也是我为什么把该系列称为<<绕不开的"锁">>. 如果小伙伴们对synchronized关键字很熟悉了,可以跳过本系列.