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

    有技术,有情怀,有温度

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

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/yaomaomao/p/11969674.html
Copyright © 2011-2022 走看看