ReentrantLock重入锁 源码解析2 (解锁)

前言

在上一篇文章中我们介绍了ReentrantLock 源码中的加锁过程https://blog.csdn.net/tynewbilar/article/details/142664486?spm=1001.2014.3001.5501

解锁过程相比较而言比较简单,笔者建议可以根据上篇文章给的流程图自己走一遍也算是熟悉读源码的感觉。同上一篇一样,笔者废话颇多,请读者通过目录拣选自己需要的部分阅读, 其中块引用区为一些小思维拓展可以直接跳过

下图为笔者自己总结的大致流程,仅供参考一切以源码为准

我们直接开始,因为解锁过程比较简单,笔者这里选择与加锁步骤步步对应来讲解,从而使我们再梳理一遍他们的联系喵

解锁!

记不记得我们加锁时候的代码

加锁时候字面翻译就叫做让他为1,而这里就是释放锁为1的情况

1是什么 ReentrantLock 有个state 变量,state 变量为0 的时候表示锁是空闲的状态,state为1 的时候表示锁被占用的状态

tryRelease

之前的加锁过程 tryAcquire 函数是由公平锁与非公平锁各自实现的,而解锁过程则不需要

其实这里可以我们可以看一下这个作者的设计思路也能有所收获。

首先不妨来想想如果你没看过这个源代码你会怎么设计RenntratLock?

笔者才疏学浅自然而然的想法就是设计一个类 RenntraLock 然后 再创建公平与非公平锁继承他

来思考一下这样写的可行性,先写一个RenntraLock类里面封装一些 二者公共的函数比如 release

然后再来写 公平锁与非公平锁来继承 RenntraLock 那么问题来了,他们继承了RenntraLock而java 规定的继承只能继承一个 那AQS 没地方继承了 如何解决?

1. 将RenntraLock  写成接口。这样做符合规定但公平锁和非公平锁的代码会十分臃肿

2.将AQS 的功能写进RenntraLock 里面,这样做确实能够解决问题,但是将一个队列和RenntraLock 耦合化了,让代码变得笨重且局限

等等其他解决思路其实都不能很好的解决问题

况且假设它成功解决了

在使用过程中会变成  MyFairSync  ms = new MyFairSync();

                                    ms,lock;

                                   

                                   MyUnFairSync  mns = new MyUnFairSync();

                                    mns,lock;

作为一个api使用者 我们往往希望尽可能忽略它的实现方式重视它使用是否便利,而上面这种便不如  

ReentrantLock reentrantLock = new ReentrantLock(true); 使用起来清爽

这里说这么多也是笔者在感慨设计模式的重要性,一个程序它的内在效率高低自然重要,但他面向使用者的形式的重要性也不容小觑。

而对我们程序员来说呢? 提高自己的技术能力固然重要,而对于我们来说社交能力,团队合作能力,表达能力等的重要性甚至更甚于前者(好吧好吧我承认我是在氵字数,但仁者见仁智者见智吧)

书归正文

首先是第一行,这一行就是解决重入的问题,我们知道在加锁的时候如果发现当前持有锁的线程就是我自己那么就 state+1 ,自然到这里解锁就给state -1 这样说可能有点抽象来个图吧

在这里嵌套加锁时最后一个Lock 的一定是最先解锁的那么加锁时依次加1解锁时依次减一即可。这就是解决单一线程在获取锁之后反复来自己争夺自己的解决思路,也就是重入锁重入之名的来源

接下来判断一下当前线程是不是持有锁的线程不是的话直接抛错就ok( 你都没有拿到锁那你凭什么释放锁啊)

接下来如果当前 state == 0 就直接 将持有锁线程设置为空 返回true 到这里只是标识上改变了但并未彻底完成释放锁的操作,所谓释放锁当然是空出来锁允许其他人竞争的意思

不为0 就一个cas操作 设置state 为 -release 后的状态 返回false

unpark

在tryRelease 返回 true 以后获取头节点 如果头不为空(为空则表示只有这一个线程竞争,或者说所有线程都是在交替有序竞争就不需要创建AQS 队列,自然也不需要解除后续节点的阻塞了)并且头节点的waitState 不为0(为0就表示这个队列就剩下它一个了,那他这个锁释不释放都是个口头问题的了,因为都没人与他竞争他想怎么样怎么样) 则unpark 这个头节点的下一个的下一个节点

unparkSuccessor

这里是个比较重要的点 !

记得在 tryRelease 的时候 将state 改成0了

而这个时候我在上一篇文章中就说过排在队伍第二位得人有资格不断询问第一个人释没释放锁资源,而从第三个人往后都阻塞住 一旦这个时候state 为0那队伍中第二位得人就立刻拿到了锁并且将state 设置为1 且将持有锁线程改为自己,前一个人出队列,他自己变成队头,从而当前队列中第二位(之前被阻塞的队列中3号位,变成2号位,获得了询问队头释没释放锁得资格所以它要取消阻塞状态)这里看不懂得要多看即便,自己画图模拟模拟

这时再看代码的内容是不是就清楚很多了,有些写在流程途中得内容就不重写了

小结

如果大家喜欢得话欢迎留言不懂的部分或者还想看与之相关的什么源码讲解,谢谢支持喵

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小户爱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值