一文带你深入理解——锁的可重入性
  TEZNKK3IfmPf 2024年03月30日 23 0

概述

        简而言之,一个线程,连续针对一把锁,连续加锁两次或以上,就有可能出现两种情况,一种是产生死锁,这样的锁叫做“不可重入锁”,另一种是不会产生死锁,这个锁叫做“可重入锁”;


深入理解

什么是死锁?

        一个有趣的比方,假如,你是八路军~ 的一个秘密的电报员,在入敌深处,建立了一个隐蔽的房间专门给组织发送机密电报;这次你又发现了重要敌情,准备给组织发送情报,那么这么重要的事肯定不能敞开天窗大门来干,于是呢,你关上大门,为了防止闲杂人等误入,你就给门上了锁...发送完情报,忽然发现门外有很多日军在闲逛!!!为了避嫌,你选择了从这个只有你知道的地下道出去~ 过了一阵一段时间,你的同事,也来这个地方发送情报,发现门锁了!他以为你在里面发送重要情报,就没有打扰你,于是就一直在门口等下去了......     

让我们来看看实际的代码中是如何出现的吧!(如下代码)

一文带你深入理解——锁的可重入性

  这就产生了死锁!也就是说,当一个线程对一把锁,连续加锁两次;

        分析:第一次加锁,可以加锁成功,第二次加锁,就会失败,因为锁以及被占用,于是会一直在这里阻塞等待,等到第一把锁解锁,第二把锁才能加锁成功,但想要第一把锁解锁,需要执行完synchronized代码块,才可以加下一把锁,然而第二把锁一直在阻塞等待,所以第一把锁既不能解锁,第二把锁也不能加锁,就卡在这里了;

有的人可能就会说:俺作为一个优秀的程序员,怎么会写出这样的代码呢?


优秀名句——我写的代码怎么会有BUG呢?


但实际上却是防不胜防——例如多次嵌套,直观上看出不来~

一文带你深入理解——锁的可重入性

你看!这BUG,他不就来了吗!

        但实际上,以上程序不会死锁,这就关系到synchronized关键字的底层设计了...

如何解决以上问题呢?(可重入锁的底层逻辑是什么?)

        实际上它的底层很简单,只要让这个锁记住,是哪个线程持有这把锁就OK~

        什么意思呢?两次连续加锁:假设 t1 线程通过this来加锁,那么这个this里面就记录了是t线程持有的他,第二次加锁的时候,再一看锁,如果还是 t1 线程,就直接通过,不会再有阻塞等待!

        这又是怎么做到的呢?实际上是引入了一个计数器,每次加锁,计数器就++,解锁的时候计数器就--,若计数器为零,这时候才可以进行加锁(真加锁),同样,若计数器为零,此时才真正解了锁(真解锁);

计数器还未归0,程序就抛出异常,会不会死锁?

        分析:若程序抛出异常,并且没有catch捕捉,程序就会脱离之前的代码块,一旦脱离这层加锁的代码块,计数器就会--,脱离多层代码块,计数器减到0,也就解锁了;

        总结:加锁时若出现异常,是不会死锁的,也是一个使得synchronized优秀到将他设计成关键字的原因了,若是C++/Python加锁解锁,都是通过对象来实现的,这时就有可能由于出现异常引起代码未执行完,解锁代码未执行引起死锁;

面试题:可重入锁的实现要点

  • 让锁持有线程对象信息,记录是谁加的锁;
  • 维护一个计数器,用来判定是什么时候真加锁,什么时候真解锁,什么时候是直接放行。
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2024年03月30日 0

暂无评论

推荐阅读
TEZNKK3IfmPf