面试神问:说说锁的实现原理—1,为什么会有锁?
wxin55 2024-10-26 16:33 9 浏览 0 评论
文章目录
- 问题来源
- 什么叫锁
- 为什么会有锁
- 私有制和公有制
- 资源的稀缺和充足
- 保证隐私
- 僧多肉少
- 为什么会有锁
- 都有什么样的锁
- 讲不讲素质要不要排队—公平锁和非公平锁
- 虽然很多人排队,但里边未必没有坑位—乐观锁和悲观锁
- 进了大门,能不能直接进入具体坑位—可重入锁和不可重入锁
- 一个坑位只能蹲一个人,那坑位外边的洗手区呢—共享锁和排他锁
- 要不要一直排队等,还是先去旁边抽根烟—自旋锁和适应性自旋锁
- 有没有开不了的锁
- 那些被忽略的锁
- final关键字
- volatile关键字
- public、private、protected
- 神图:公厕示意图
问题来源
- 还是有一次面试呀,人家就问我:说说锁的实现原理吧。 我当时的反应就是:小朋友,你是不是有很多的问号?第一反应,可以用某某某的一首某某歌的词来形容:最想说的话,我该从何说起,你是不是也像我一样在想呢?
- 说说为什么我会有点懵逼的感觉吧。第一:在我理解,什么叫原理,就是原始的理论或者最初的道理。一个原理可以约等于一种理念,是不管谁拿着这个原理,都可以撸出一种实现的。道理只有一个,但实现方式千千万万。第二:虽说面试的时候,前提讨论背景是Java语言环境,但即使是Java里边的锁,也分很多的吧。常见通俗的,就说Synchronized关键字实现的是不是一种锁?ReentrantLock实现的是不是一种锁?ReadWriteLock实现的又是不是一种锁?第三:就上边说的这三种,在我看来也是不同类型范围的锁的不同实现方式,万万达不到原理层面。 PS:我后来知道了,他是想让我说Synchronized是怎么实现的。
- 昨天还跟一个朋友说起这个事儿,他是觉得我有点较真了,面试的时候,就是要说出对方想听的,然后大家都认可的答案。说来也奇怪,我问他:来来来,我们说说Java里边锁的实现原理吧?哇塞,他就立马开始说Synchronized的什么monitorenter和monitorexit指令,什么flag的ACC_SYNCHRONIZED标志了。我也很懵了,或许是我真的太固执吧。只是内心深处,私以为:概念、原理性的东西,一定要是清晰明确的,不能混为一谈。后来说着说着我也不想多说,就再问了朋友一个问题:好,你说了那么多非常的好,再问你一个问题:为什么会有锁? 至此,我把天聊死了。 其实,我还有好多问题呢:有无所谓的万能锁?锁的作用是啥?怎么实现自己的锁?在A场景到底需不需要锁,为什么需要锁,需要什么样的锁? 多说无益,我终究是又把天聊死了。
什么叫锁
- 《辞源》曰:“锁,古谓之键,今谓之锁。”《辞海》解释为:“必须用钥匙方能开脱的封缄器”。 再纵观历史,锁的产生,伴随着私有制的产生。不知道有么有童鞋记得中学的一篇文章《礼记-大同》中的“故外户而不闭“,不闭,咱们可以理解为不加锁的意思。
- 想一下,为什么家里的们要上锁?或者说是自己的笔记本要加开机密码—我认为设置密码,本质上就是加锁? 什么情况没有锁,换种说法是:什么情况不必有锁?
为什么会有锁
私有制和公有制
- 回到《大同》篇,人们之所以不必户,因为是大同社会呀。什么是大同社会,天下为公,就是资源是大家的,没有人有权利或者有必要把某个东西加锁。PS:额,有点类似共产主义哈。但如果用个Java关键词来说的话,大同就是public。
资源的稀缺和充足
- 想象一下我们的家为什么会有锁?怕贼偷啊,他把东西偷了,我就没有了,他富我穷。那人为什么要偷东西呢?因为他没有自己的资源。或者说资源只有一份,你现在搁家里锁起来,就意味着我没办法拥有,好东西谁都想要。但如果,资源很充足呢?就跟咱们常说的,现在有些人在路上看见一块钱,都不带弯腰去捡的,这时候敞开了送都不要,还搞个锁干啥使呢?
保证隐私
- 其实生活中还有一种情况,比如说:小姑娘在家换衣服,明明大门是锁了的,为什么还要把自己房间的们也锁上?所以有时候加锁,也因为需要很强的隐私性,我在一个空间里干了什么我不希望别人知道。
僧多肉少
- 这一点和第二点有些许不同。就是说,尽管资源很稀缺,现在手里就只有1两二师兄的肉肉,但你确定全世界就只有你一个人而已,这时候需要锁吗?就跟班里只有一个学生一样,你永远都是第一。
为什么会有锁
- 因为有些人惦记我的美貌,并想据为己有。 要么加锁藏起来保证我独自私有,要么干掉”有些人“。当我不能手染血腥”杀进程、杀线程“的时候,我只能把我自己lock起来了。PS:真要说起来,加锁是一种牺牲自己,保护别人的手段。
都有什么样的锁
- 事已至此,我要祭出大招了。请看文章结尾的图,公厕示意图。PS:历史中的博客有说过为啥我一贴图就是祭出大招。
讲不讲素质要不要排队—公平锁和非公平锁
- 大家都排着队上厕所,你说你实在很急,得了,有人能憋有人憋不得。或者有个孕妇炎炎烈日站着排队,你说这时候让不让这些很急或者很需要被照顾的人排到第一个去呢? 不让就是公平锁,管你什么呢,大家统一排队,先到先蹲坑。让了就是非公平锁,各凭本事,有些人可能来了2小时都没个坑位,有些人刚来就有坑位了。比如:ReetrantLock通过构造函数指定其的公平性,如果是公平的,那么所有的线程都加入队列中等待,先进先出。Synchronized是非公平的,没有那么个队列呀,大家来了就到门口抢呗,谁狠谁蹲坑。
虽然很多人排队,但里边未必没有坑位—乐观锁和悲观锁
- 就跟上厕所一样的,有时候根本就是下意识的看着很多人排着队,然后就以为是里边没有坑位了,然后自己还默默的加入到队伍后边,排呀排呀。突然有一个人没排队进去了,然后又XXX了一会子开门出来了。哈哈哈,其实很可能通用坑位没人用啊。或者大家都排着队想去洗洗小手,或者排队的都是女同胞,其实作为男同胞的你是有专属坑位的。Synchronized是悲观的,只要有人从大门进去了,里边就一定没有坑位了。CAS认为是乐观的,先去看看再说,有人就老实排着,没人就蹲坑。在Java里边的话,用各种锁,不仅限于Synchronized,都是一种悲观的态度,总有刁民想害朕,朕先搞把锁把自己保护起来。而无锁编程则是乐观的,虽说总有刁民想害朕,但等他来害我的时候,我再把他打死,平常我就专心练我的绝世神功。
进了大门,能不能直接进入具体坑位—可重入锁和不可重入锁
- ReetrantLock和Synchronized都是可重入锁。如图所示,一共3个坑位,钥匙有3把,只要你拿到大门的钥匙,就可以进去蹲坑。可重入锁很有好处的耶,试想一下,当你兴高采烈拿到大门钥匙的时候,总觉得下一秒就可以冲进去蹲坑,谁知道,里边的坑位还有锁,并且里边还排着一堆人,这时候,只能说你完了,完了,尿裤子了,等”si“吧,女票在外边等那么久都等不着你,等待超时,女票远走。哦豁,都完了。
一个坑位只能蹲一个人,那坑位外边的洗手区呢—共享锁和排他锁
- 一个坑位只能蹲一个人,你蹲了,我就不能蹲。但洗手区,你可以洗,我可以洗,他可以洗,咱们可以一起洗。ReentrantLock和Synchronized是排他的,我占了这个坑位,你就只能等着。但ReadWriteLock不同。虽然我拿了大门钥匙,但我只独占坑位,其他人想蹲坑需要等待,但只想洗洗小手的话,则大胆的往前走就阔以了。所以也会经常发些,公厕常理来说是不关大门甚至没有大门锁的,只是每个坑位才有关门和开门的概念。
要不要一直排队等,还是先去旁边抽根烟—自旋锁和适应性自旋锁
- 自旋锁,就是你看着有人排队,然后你一直在队伍里边排着,直到你等到了一个坑位,然后离开。炎炎烈日或者凛冽寒风,可怜的你就站在队伍里排着,很消耗生命体能的。在程序里应该是耗费CPU吧,但也有好处,就是你可以第一时间拿到坑位。适应性自旋锁,举个栗子吧:你现在看见有3个人进入大门进了小坑位了,这时候,突然有一个人出来洗小手手,但是突然她又进去蹲坑了—传说中的偏向锁。这个时候是个人都会在这等的吧,希望就在不远的前方了。—据说是轻量级的锁。但是,万万没想到啊,这人也是蹲坑界的王者,你都等30分钟了,还没有出来。等个鬼,咱不等了。然后大喊一声:里边的勇士,假如出坑了,请大喊一声有坑位了,小的立马就来。——好像是重量级的锁。这时候,有好处也有坏处。好处就是不用一直站着等啊,坏处就是得来回跑,其实哪个耗费体能多,还真说不准,看等待的时间长短吧。
有没有开不了的锁
- 不知道有缘路过的众位勇士有木有经历过这么一个名场面。厕所里边的人出不来,厕所外边的人进不去,大家一直在吵吵,有些本来想蹲坑后来又不想的人被困在里边,有些本来只是进去洗个小手手的人,也被困在里边。我是在春运的时候,在火车站经历了N次这样的名场面。这其实,就是一把开不了的锁。而且除了有坑位的门这种有形的锁,还有想挤出来的人,和想挤进去的人之间形成的无形的锁。也再次说明,锁是一个抽象概念,不是一个具体的实物。在Java编码中也是一样的,并不一定是咱们声明了一把锁,比如用个Synchronized或者别的啥啥啥,才会有锁的出现。比如说你明明就没有声明锁呀,结果整个进程都形成死锁了。所以,但凡有资源竞争的地方,都不是挂了一把锁,才有锁的,锁是个保护机制。
- 从原则上说,没有开不了的锁,也没有一定要开的锁。根据加锁的不同目的,和获取锁的不同目的,可以有分别不同的行为。问题是:是否愿意放弃被锁住的东西?是否愿意去保护被锁住的东西?被锁住的东西是否能有个完美的替换品?但一个线程一定要完整获取被锁住的那个东西时,而锁住东西的那个线程不愿意放手时,这就是一把开不了的锁—死锁。形成死锁的四个条件:互斥条件、请求与保持条件、 不剥夺条件、循环等待条件。对于编程而言是锁,是死锁。对于人而言,就是结,死结。只要愿意有任意一方任意一个环节作出让步,都不会有开不了的锁。
那些被忽略的锁
- 难道只有Synchronized、ReentrantLock这呀那的才算是锁吗?那CAS也没个锁的意思,可也还是锁呀。所以锁终归只是一种抽象的东西,只是一种约定:我上了锁,大家都不许破坏争抢。有将约定实体化的,也有放得开看得透不搞锁的。
final关键字
- final关键字修饰的类、方法、变量,不允许被修改。什么不能被继承啊,什么不能被重写可以重载呀,咱们都先不说。这个关键字,真是太大气也太慈悲了,为什么这么说呢,这资源是我的呀,我插上旗帜落下我自己的记号已经成为我独有的了。我本可以通过围栅栏,加锁的方式让其他人都得不到。但是,我把资源加上保护罩,公开陈列展出,允许你看,允许你用,甚至允许你山寨,只要你不破坏我原来的样子就可以了。像String,Integer、Array、Math等,我所有的好东西,大家谁都可以看看,拿着用。有时候,我们为什么要加锁,不过就是因为我不希望属于我的东西,被别人改动破坏。所以,保证私有,有时候的本质目的其实是保证不可变就阔以了。
volatile关键字
- 如果说final关键字大气又慈悲,volatile关键字就跟个慈善家似的。别人家的公厕只能在外边排队等,但volatile家的允许你进去洗手区域等。一旦有人出坑,你立马就可以进去。而不是像排队在外边的人一样,就算有人出了坑位在洗手,他也依然在等待,甚至是以为里边没有可用坑位而原地爆炸。volatile是个善良的人,但善良的人也会有底线,底线就是:当一个人想进,一个人想出的时候,必须先出才能进,传说中的指令重排。要说这个关键字没有锁么?不见得。如果没有锁,为什么必须先出才能再进呢?只是锁的不那么明显。
public、private、protected
- 这些访问控制关键字,从对自己所持资源的开放程度来说,也能是不同程度的锁。不想说了,突然很困,睡觉来着的。
神图:公厕示意图
相关推荐
- ES6中 Promise的使用场景?(es6promise用法例子)
-
一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...
- JavaScript 对 Promise 并发的处理方法
-
Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...
- Promise的九大方法(promise的实例方法)
-
1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...
- 360前端一面~面试题解析(360前端开发面试题)
-
1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...
- 前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?
-
Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...
- 最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式
-
看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...
- 前端分享-Promise可以中途取消啦(promise可以取消吗)
-
传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...
- 手写 Promise(手写输入法 中文)
-
前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...
- 什么是 Promise.allSettled()!新手老手都要会?
-
Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...
- 前端面试-关于Promise解析与高频面试题示范
-
Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...
- 宇宙厂:为什么前端离不开 Promise.withResolvers() ?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...
- Promise 新增了一个超实用的 API!
-
在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...
- 一次搞懂 Promise 异步处理(promise 异步顺序执行)
-
PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...
- Promise 核心机制详解(promise机制的实现原理)
-
一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...
- javascript——Promise(js实现promise)
-
1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- ES6中 Promise的使用场景?(es6promise用法例子)
- JavaScript 对 Promise 并发的处理方法
- Promise的九大方法(promise的实例方法)
- 360前端一面~面试题解析(360前端开发面试题)
- 前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?
- 最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式
- 前端分享-Promise可以中途取消啦(promise可以取消吗)
- 手写 Promise(手写输入法 中文)
- 什么是 Promise.allSettled()!新手老手都要会?
- 前端面试-关于Promise解析与高频面试题示范
- 标签列表
-
- hive行转列函数 (63)
- sourcemap文件是什么 (54)
- display none 隐藏后怎么显示 (56)
- 共享锁和排他锁的区别 (51)
- httpservletrequest 获取参数 (64)
- jstl包 (64)
- qsharedmemory (50)
- watch computed (53)
- java中switch (68)
- date.now (55)
- git-bash (56)
- 盒子垂直居中 (68)
- npm是什么命令 (62)
- python中+=代表什么 (70)
- fsimage (51)
- nginx break (61)
- mysql分区表的优缺点 (53)
- centos7切换到图形界面 (55)
- 前端深拷贝 (62)
- kmp模式匹配算法 (57)
- jsjson字符串转json对象 (53)
- jdbc connection (61)
- javascript字符串转换为数字 (54)
- mybatis 使用 (73)
- 安装mysql数据库 (55)