关注公众号【1024个为什么】,及时接收最新推送文章!
本文内容:
1、为什么面试官总爱问底层原理?
2、为什么看了很多遍,却还是记不住?
3、为什么去了趟银行就理解线程池了?
为什么面试官总爱问底层原理?
别的面试官都在问
我相信有一部分面试官有这样的想法,只不过是占少数而已。他们会在网上找一些面试题,自己大概研究一下(有的自己也稀里糊涂),就拿来考核应聘者。如果只是聊基本的使用,不拿底层原理为难为难你,不仅显得自己的技术水平一般,也彰显不出公司的技术实力。
确实能区分出不同层次的程序员
那些经典的面试题,相信大家都耳熟能详,而线程池的底层实现可谓是经典中的经典。
但是在日常的业务开发中,很少会用到多线程,线程池就更少了。所以,知不知道底层原理,就可以看出你是不是对技术有一定的钻研精神,是不是一个有技术追求、对自己要求更高的程序员。虽然大家都心知肚明:如果不是为了面试,老子才不看什么原理呢
懂得原理才有可能打造出高效可靠的服务
可能很多人不认同这一点,觉得装 X。
这一点我想着重说一下,曾经我也对此嗤之以鼻,感觉工作中又用不到,看了确实没什么用。后来服务真正出问题的时候,因不懂原理而无从下手,慢慢的才体会到底层原理的重要性。
•知道了底层实现,才能正确的使用
我们用的语言、框架、插件等等,都可以看做是别人发明的工具。我们没必要重复发明工具,只要用好这些工具,开发出预期的业务产品即可。
但前提是你要了解这些工具,才能用的得心应手。就像刀具为什么分那么多种类,有用来剁的、有用来切的、有用来雕刻的。你非要拿雕刻刀来切片(就好比非要和 Redis 的持久化较劲),也不是不可以,自己体会吧。
•可以快速定位、解决问题
举个例子:
老式的摆钟,经常走不准,不是快就是慢。如果不懂原理,就只能在偏差大的时候把指针拨回到正确的位置(就像有些线上问题,找不到原因,但重启就没问题了,就只能在出问题的时候重启服务)。
这肯定不是长久之策,我们要研究其原理,走的快的时候说明钟摆摆动的快,可以适当往下放一放,半径长了,摆动就慢了;反之亦然。
对应到我们的服务也是一个道理。
•学习前辈们的经验,少跳坑
了解底层原理,不仅仅是为了排查问题(能遇到底层的问题也是看缘分的),更重要的是吸收它们的通用解决方案。很多线程级别的问题解决思路,放大到服务级别也同样适用。
我们都知道线程池有任务队列,放大到服务级别,我们用消息队列来解决服务节点收到的大量请求是一个道理。
为什么看了很多遍,却还是记不住?
还是看的少
我们大都是普通人,没有过目不忘的能力。记得高中英语老师说过,记忆的秘诀就是“重复”。
用得少
如果让你用 switch ... case 实现一段判断逻辑,是不是要思考一段时间;
但如果让你用 if ... else 来实现,可能就不假思索的写出来了,因为我们天天用、天天写,都快形成肌肉记忆了。
方法不对
有些确实不常用的,想长久不忘也不现实。理工科的很多知识都不用死记硬背的,学会推理,就不必担心记不住了。虽说记忆没什么诀窍,但前提是要理解了,难以理解的就想办法和自己身边的事物联系起来,形成关联记忆。从能记住的简单知识点,一步一步推理,浮现出复杂的知识点。
扯了这么多有的没的,都是大道理,空理论。还是要啰嗦一句,
理论指导实践
,想想马克思为什么这么伟大,这句话就不难理解了。
为什么去了趟银行就理解线程池了?
先设定一个场景,某银行网点,今天15:00 发售某个理财产品,收益 6%(收益诱人,购买的人估计要排队了)。
早上刚开门是这个样子的
还没有人来办理业务(绝大多数业务都可以在线上办理了,我上一次去银行还是身份证到期,需要去网点重新认证
),总共 4 个窗口,只开了 2 个,休息区有 8 个座椅,等待着客户的到来。
对比线程池:
刚初始化好,核心线程数
=2,最大线程数
=4,线程工厂
产生的线程名前缀都是“理财-00”,队列
可放 8 个任务, 拒绝策略、非核心线程存活时间 后面会提到。
不一会,来了 2 个办理理财赎回业务的
取号后(如果中途补充材料,再次进入无需重新取号),两个窗口正好为这 2 人服务。
对比线程池:
有任务进来了,取号就相当于可重入锁
,2 个核心线程
被占用,未达到最大线程数
,队列
是空的。
由于人一直不多,两个窗口一直忙忙碌碌,但也能应付的了。
快到15:00
了
一下来了 3 个人,大堂经理会说:窗口都在忙,拿个号先在休息区等一会儿吧。银行不会因为少量的客户等待而新开服务窗口
。
对比线程池:
又有任务进来了,2 个核心线程
被占用,队列未满,先去排队,队列里有3个任务
。原则就是不能刚有任务堆积,就新起线程。
到15:00
了
这次一下又来了 5 个人,大堂经理还是安排客户在休息区等候,休息区已坐满。
对比线程池:
又有任务进来了,2 个核心线程
被占用,队列未满,继续排队,队列里增加到了8个任务
,队列已满。
此时,来了一个 VIP 客户
大堂经理一看休息区都坐满了,再不开新窗口办理业务,VIP 估计要投诉了。于是就协调新开一个窗口给VIP办理业务。休息区的客户表示不服啊,凭什么他插队?不服也不行,世界就是这么不公平。
对比线程池:
又有任务进来了,2 个核心线程
被占用,尚未达到最大线程数
,新起了 1 个非核心线程
,新任务利用可重入锁的非公平
特征直接抢到了非核心线程,队列仍然满位
,一朝排队,永久排队。
又来一个 VIP 客户
还有一个窗口没有开放,大堂经理只好又协调新开一个窗口办理业务。
对比线程池:
又有任务进来了,2 个核心线程
被占用,尚未达到最大线程数
,又新起了 1 个非核心线程
,被新来的任务抢到了,队列仍然满位
,此时已达到最大线程数。
仍然有买理财的客户过来
大堂经理看了一下剩余的理财额度,正好能被排队的人买完。于是就告知客户,理财已售完,下次再来吧。
对比线程池:
又有任务进来了,2 个核心线程
被占用,2 个非核心线程
被占用,达到了最大线程数,队列里任务已满
,触发了拒绝策略
。如果自己实现拒绝策略,需要明确的告诉任务拒绝的原因,方便定位问题。如果不直接拒绝,也可以把任务引导到其他地方执行,比如 MQ。具体实现视业务场景而定。
终于办理完所有客户的业务了
对比线程池:
没有新任务进来,2 个核心线程
空闲中,2 个非核心线程
空闲中,队列为空
。
16:30
快下班了,应该不会有太多人来了。大堂经理对1、4 号窗口的说:再等5分钟,人不多的话,就关闭窗口,暂停服务。
对比线程池:
没有新任务进来,2 个核心线程
空闲中,2 个非核心线程
等了5分钟(非核心线程存活时长、时间单位
)后发现没有新的任务需要执行,自行销毁,队列为空
。
还有几点没提到的
1.窗口在不知道是否还有人等待办理业务时,会一直按叫号器的下一个,直到没有。类似于线程池阻塞的去取任务;2.每个线程都是有状态的,类似于窗口上屏幕展示的“xxx 号正在办理业务”;3.线程池有自己的计数器,可以清楚的知道处理过多少任务,当前有队列多少任务等等,这些数据银行也有记录,在取号机都可以得到。
总结
1.底层原理确实重要;2.线程池的几大核心要素,上面的例子基本都涵盖了;3.线程池考虑到的问题及解决方案,服务节点也要考虑,也要给出服务级别的解决方案;4.生活中问题的解决方案,在开发中同样适用;
比如,我有几套房子要出租,自己又没有时间和精力去和租户对接,干脆就交给中介吧,专业的人做专业的事。这就好比我们的注册中心,服务的提供方和调用方不用一对一对接,加个中间层,交给注册中心去处理。