一文带你看懂Java中的Lock锁底层AQS到底是如何实现的(三)

pivoteic
发布于 2022-6-16 17:46
浏览
0收藏

 

释放锁

ok,说完加锁的过程之后,我们来看看释放锁干了什么。

 

ReentrantLock的unlock其实是调用AQS的release方法,我们直接进入release方法,看看是如何实现的

一文带你看懂Java中的Lock锁底层AQS到底是如何实现的(三)-鸿蒙开发者社区

进入tryRelease方法,看一下Sync的实现

一文带你看懂Java中的Lock锁底层AQS到底是如何实现的(三)-鸿蒙开发者社区

其实很简单,就是判断锁的状态,也就是加了几次锁,然后减去释放的,最后判断释放之后,锁的状态是不是0(因为可能线程加了多次锁,所以得判断一下),是的话说明当前这个锁已经释放完了,然后将占有锁的线程设置为null,然后返回true,

 

然后就会走接下来的代码。


就是判断当前链表头节点是不是需要唤醒队列中的线程。如果有链表的话,头结点的waitStatus肯定不是0,因为线程休眠之前,会将前一个节点的状态设置为-1,上面加锁的过程中有提到过。

 

接下来就会走unparkSuccessor方法,successor代表继承者的意思,见名知意,这个方法其实就会唤醒当前线程中离头节点最近的没有状态为非取消的线程。然后调用LockSupport.unpark,唤醒等待的线程

一文带你看懂Java中的Lock锁底层AQS到底是如何实现的(三)-鸿蒙开发者社区

然后线程就会从阻塞的那里苏醒过来,继续尝试获取锁。


我再次贴出这段代码。

一文带你看懂Java中的Lock锁底层AQS到底是如何实现的(三)-鸿蒙开发者社区
获取到锁之后,就将头节点设置成自己。

 

对应我们的例子,就是线程1释放锁之后,就会唤醒在队列中线程2,先成2获取到锁之后,就会将自己前一个节点(也就是头节点)从链表中移除,将自己设置成头节点。该方法就会跳出死循环。

一文带你看懂Java中的Lock锁底层AQS到底是如何实现的(三)-鸿蒙开发者社区

到这里,释放锁的过程就讲完了,其实很简单,就是当线程完完全全释放了锁,会唤醒当前链表中的没有取消的,离头结点最近的节点(一般就是链表中的第二个节点),然后被唤醒的节点就会获取到锁,将头节点设置为自己。

 

总结

 

相信看完这篇文章,大家对AQS的底层有了更深层次的了解。AQS其实就是内部维护一个锁的状态变量state和一个双向链表,加锁成功就将state的值加1,加锁失败就将自己当前线程放入链表的尾部,然后休眠,等待其他线程完完全全释放锁之后将自己唤醒,唤醒之后会尝试加锁,加锁成功就会执行业务代码了。

 

文章转自公众号:三友的java日记

标签
已于2022-6-16 17:46:23修改
收藏
回复
举报
回复
    相关推荐