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

人生之路不会是一帆风顺的,我们会遇上顺境,也会遇上逆境,在所有成功路上折磨你的,背后都隐藏着激励你奋发向上的动机,人生没有如果,只有后果与结果,成熟,就是用微笑来面对一切小事。

导读:本篇文章讲解 一文带你深入理解——锁的可重入性,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

目录

概述

深入理解

什么是死锁?

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

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

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


概述

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


深入理解

什么是死锁?

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

  • 让锁持有线程对象信息,记录是谁加的锁;
  • 维护一个计数器,用来判定是什么时候真加锁,什么时候真解锁,什么时候是直接放行。

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

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/124328.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!