zoukankan      html  css  js  c++  java
  • 面试官:多线程一定比单线程跑得快吗?

    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、数据库的性能调优,有……

    有技术,有情怀,有温度

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

  • 相关阅读:
    银联测试
    mysql 往表中某个字段的字符串后追加字符串
    jsp通过js往后端传文字时乱码问题的解决
    artTemplate 如何遍历数据
    Error:java: Annotation processing is not supported for module cycles. Please ensure that all modules from cycle [kstore_goods_platform,kstore_goods,kstore_custom] are excluded from annotation processi
    递归方式实现二分查找
    递归与二分查找
    python内置函数
    函数的四种传参方式
    python基础(四)
  • 原文地址:https://www.cnblogs.com/yaomaomao/p/11969674.html
Copyright © 2011-2022 走看看