上善若水,不进则退

姚毛毛

左手代码,右手写诗

linuxido.com

面试官:多线程一定比单线程跑得快吗?

Part 1 思考人生的多线程

我们一直在说高并发、多线程、分布式应用,但是高并发情况下,多线程一定就快吗?

我们首先要理解下并发运行是怎么一回事。

为什么一般意义上来说多线程就能抵抗高并发,运行速度就能得到提升?

所谓并发运行就是某个时间段CPU能执行多个任务。

例如早上起来后,刷牙、照镜子、思考这复读机一般的人生是为哪般?

但是我们真的能同时做这么多事吗?

不是的,其实是在大脑下达指令后,刷牙、照镜子这种动作已经形成了肌肉记忆、固定动作,然后我们又有了几分钟思考人生的时光了。

同样的道理放在计算上也是一样。

我们首先要明白一个基础知识,计算机的主要组件为CPU、内存、磁盘;而在这三大组件中,CPU的运行速率高于内存1000倍以上,内存的运行速率高于磁盘1000倍以上。

当然,这只是我的口嗨,并不是真的1000倍。

你只要知道他们的运行速率对比,CPU > 内存 > 磁盘就好了,并且要快很多。

Part 2 应付多个婴儿的哺乳妈妈

2.1 上下文切换

多线程执行就像是很多个婴儿跟妈妈要奶喝一样,怎么办?妈妈就两个哺乳器官啊?最多就同时处理两个婴儿同时肚子饿的任务。

这已经是双核CPU了。实际上,妈妈只能同时处理一个婴儿哺乳的任务而已,没办法同时把两个孩子抱在怀里。你以为是母猪可以同时喂很多小猪呢?

所以只好让婴儿先喝点,抵抵饱,哄一哄,然后换另外的孩子。

这就是CPU的【上下文切换】。

2.2 线程争用

而很多时候,我们需要运行的任务并不是一样的。

还是以婴儿为例,婴儿们同时大哭,要求占用妈妈的时间,ABC婴儿要换尿布、DEF婴儿要喝奶。

怎么办?头大。

这就是【线程争用】。

2.3 并发执行

妈妈要开始安抚孩子了,但是只能一个个来啊,要么先找几个奶瓶冲奶让要喝奶的自己抱奶瓶喝奶,再去处理换尿布。

要么先去处理尿布,再去冲奶。

冲奶这个动作很快,但是喝奶的时间很长。妈妈考虑了下,决定先冲奶,然后让他们自己抱奶瓶。

这就是【并发执行】。

2.4 自旋锁

但是冲奶的时候,婴儿还在哭,等待着妈妈送来奶瓶和换尿布怎么办?

这就是【自旋锁】。如果CPU一直不处理任务,就循环等待,直到CPU来处理。

2.5 互斥锁

如果妈妈冲奶时,抱了一个婴儿在怀里哄着不哭,其他的婴儿们没指望了,就不哭了(当然,实际上不可能),等着妈妈空出手来又继续哭,竞争妈妈的怀抱(笑)。

这就叫【互斥锁】。它跟自旋锁类似,不同的是竞争不到锁的线程会回去睡会觉,等到锁可用再来竞争。竞争失败者继续回去睡觉直到再次接到通知。

2.6 乐观锁

如果DEF拿到了奶瓶就不哭了,直到一瓶奶喝完还是喝不饱,才开始哭,要妈妈。这叫【乐观锁】。

乐观锁在数据库的数据操作中,就是提交更新那一刻,才给相关数据行加锁。

2.7 悲观锁

如果DEF拿到了奶瓶还是哭,因为他们还需要妈妈抱着喝才行。这叫【悲观锁】。

悲观锁就是如果一个事务操作用了锁,那只有当这个事务把锁释放(把妈妈给释放),其他事务才能够执行与该锁冲突的操作。

2.8 时间片分配算法

我们观察以上的故事,可以发现它们并不是同时运行的。

而CPU相比妈妈来说,它的执行速度就更快了,它通过给每个线程分配CPU时间来实现任务运行,这个时间片一般是几十毫秒。

这样不停地来回切换任务,运行程序,划分时间片,就叫做【时间片分配算法】。

2.9 线程与进程

上面说的是一个哺育室的故事,以JAVA而言,这就是一个【进程】。

如果妈妈还管着另一个哺育室,就又是一个进程。

一个哺育室有很多婴儿,婴儿们也可以认为是一个个线程。

所以【一个进程可以包含多个线程】。

而婴儿们又享受着哺育室的公共环境与玩具。这就是【内存环境共享】。

在Java应用中,每个线程都是运行在进程的上下文中,共享【同样的代码和全局数据】。

如果其中一个哺育室的装修风格、哺育规则变了,也不会影响到另一个哺育室。

所以在多进程环境中,任何一个进程的终止,都不会影响到其他进程。

所以在单核CPU时代,我们在一台电脑上也可以同时听歌、写作,可以一边看电影、一边论坛灌水【多进程】,而一个论坛里又可以有多个用户同时灌水【多线程】。

part 3 多线程一定比单线程跑得快吗?

回到最初的话题。

面试官:

如果有很多任务,每个任务需要CPU处理的时间都很长,占用的时间片很高,那么,多线程还能快吗?

如果任务很少的情况下又是怎么样呢?

例如只有两个婴儿,来回换着哺乳快还是一个个喂饱来得快呢?

什么情况下适合使用多线程呢?

除了CPU、内存、磁盘,还有什么能影响并发执行的速度呢?

 

如果你是面试者,怎么回答呢?留言给我说说看你的看法。

如果你对我上面的解释并不满意,有着不同的看法,也欢迎来喷一喷。

--------------------------------------------------------
欢迎关注我的公众号:姚毛毛的博客

这里有我的编程生涯感悟与总结,有Java、Linux、Oracle、mysql的相关技术,有工作中进行的架构设计实践和读书理论,有JVM、Linux、数据库的性能调优,有……

有技术,有情怀,有温度

欢迎关注我:姚毛毛& 妖生

posted @ 2019-12-02 11:39  姚毛毛  阅读(5000)  评论(7编辑  收藏  举报