文章目录

  • 文章目录
  • 问题的根源
  • 什么是锁?
  • 为什么有锁?
  • 私有制和公有制
  • 资源的稀缺和充足
  • 保证隐私
  • 僧多肉少
  • 为什么有锁?
  • 有哪几种锁?
  • 不谈质量。该不该排队——公平锁和不公平锁?
  • 虽然很多人排队,但里面未必没有坑——乐观锁和悲观锁。
  • 入闸后可以直接入特定的坑——重入锁和不重入锁吗?
  • 一个坑只能蹲一个人。坑外洗手区呢——共享锁和独占锁?
  • 是要一直排队,还是先在旁边抽根烟——旋锁和自适应旋锁?
  • 有打不开的锁吗?
  • 那些被忽视的锁
  • 最终关键字
  • 挥发性关键字
  • 公共、私人、受保护
  • 上帝:公共厕所示意图

文章目录

问题来源什么叫锁为什么会有锁私有制和公有制资源的稀缺和充足保证隐私僧多肉少为什么会有锁都有什么样的锁讲不讲素质要不要排队—公平锁和非公平锁虽然很多人排队,但里边未必没有坑位—乐观锁和悲观锁进了大门,能不能直接进入具体坑位—可重入锁和不可重入锁一个坑位只能蹲一个人,那坑位外边的洗手区呢—共享锁和排他锁要不要一直排队等,还是先去旁边抽根烟—自旋锁和适应性自旋锁有没有开不了的锁那些被忽略的锁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关键字修饰的类、方法、变量,不允许被修改。什么不能被继承啊,什么不能被重写可以重载呀,咱们都先不说。这个关键字,真是太大气也太慈悲了,为什么这么说呢,这资源是我的呀,我插上旗帜落下我自己的记号已经成为我独有的了。我本可以通过围栅栏,加锁的方式让其他人都得不到。但是,我把资源加上保护罩,公开陈列展出,允许你看,允许你用,甚至允许你山寨,只要你不破坏我原来的样子就可以了。像String,Integer、Array、Math等,我所有的好东西,大家谁都可以看看,拿着用。有时候,我们为什么要加锁,不过就是因为我不希望属于我的东西,被别人改动破坏。所以,保证私有,有时候的本质目的其实是保证不可变就阔以了。

挥发性关键字

如果说final关键字大气又慈悲,volatile关键字就跟个慈善家似的。别人家的公厕只能在外边排队等,但volatile家的允许你进去洗手区域等。一旦有人出坑,你立马就可以进去。而不是像排队在外边的人一样,就算有人出了坑位在洗手,他也依然在等待,甚至是以为里边没有可用坑位而原地爆炸。volatile是个善良的人,但善良的人也会有底线,底线就是:当一个人想进,一个人想出的时候,必须先出才能进,传说中的指令重排。要说这个关键字没有锁么?不见得。如果没有锁,为什么必须先出才能再进呢?只是锁的不那么明显。

公共、私人、受保护

这些访问控制关键字,从对自己所持资源的开放程度来说,也能是不同程度的锁。不想说了,突然很困,睡觉来着的。

上帝:公共厕所示意图