ReentrantLock 源码解读
创始人
2024-05-30 21:48:14
0

一、ReentrantLock

ReentrantLockjava JUC 中的一个可重入锁,在上篇文章讲解 AQS 源码的时候提到 ReentrantLock 锁是基于 AQS 实现的,那是如何使用的 AQS 呢,本篇文章一起带大家看下 ReentrantLock 的源码。

AQS 中,如果需要使用AQS的特征则需要子类根据使用的场景,重写下面方法,

//查询是否正在独占资源,condition会使用
boolean isHeldExclusively()	
//独占模式,尝试获取资源,成功则返回true,失败则返回false
boolean tryAcquire(int arg)
//独占模式,尝试释放资源,成功则返回true,失败则返回false
boolean tryRelease(int arg)
//共享模式,尝试获取资源,如果返回负数表示失败,否则表示成功。
int tryAcquireShared(int arg)
//共享模式,尝试释放资源,成功则返回true,失败则返回false。
boolean tryReleaseShared(int arg)

由于这里 ReentrantLock 锁的特性,所以下面我们只需关注独占模式下的几个方法即可。

说明:本文中关于 AQS 中的方法没有做过多的解释,不了解的小伙伴可以看下这篇对 AQS 源码分析的文章,和当前文章在同一专栏:

https://blog.csdn.net/qq_43692950/article/details/129367736

下面一起开始 ReentrantLock 源码的分析:

二、ReentrantLock 的 Sync、FairSync、NonfairSync

2.1 Sync、FairSync、NonfairSync

在声明 ReentrantLock 锁时,有两种方式,一种是无参构造函数,一种则需要指定一个 fair 参数:

new ReentrantLock();
new ReentrantLock(false);

当使用无参构造函数声明时,则是创建了一个 NonfairSync 对象:

在这里插入图片描述

通过有参的构造函数,则根据传入的 fair 可以选择创建一个 FairSync 对象:

在这里插入图片描述

其实这里也不难理解 NonfairSyncFairSync 其实就是ReentrantLock 锁中的非公平锁和公平锁两种类型。

点到这两个类中,可以看到都继承自 Sync 类:

在这里插入图片描述
在这里插入图片描述

Sync 类,则继承了 AQS

在这里插入图片描述

到这里了,我们寻找几个关键的方法,在AQS中独占模式下,两大关键的方法是交由子类进行实现的,分别是 tryAcquire 尝试获取资源,和 tryRelease 尝试释放资源。

首先来看 tryAcquire 尝试获取资源:

通过 Sync 类的实现源码发现并没有重写 tryAcquire 方法,那该方法肯定在下面的子类FairSyncNonfairSync ,分别看下源码确实存在重写的方法:

在这里插入图片描述
在这里插入图片描述

2.2 NonfairSync 下的 tryAcquire

首先看下 NonfairSynctryAcquire 实现逻辑,可以看到又调用了 nonfairTryAcquire 就是 Sync 类中的 nonfairTryAcquire ,从命名上可以分析出就是非公平锁的尝试获取资源,直观就是非公平锁下获取锁操作:

在这里插入图片描述
进入到 Sync 类中的 nonfairTryAcquire中,可以看到首先获取到 AQS 中的共享资源 state,如果 state 等于 0 ,则将 state 的值修改为 acquires(默认为1,下面会分析到),并设置AQS的独占线程为当前线程,并返回 true ,说白了不就是获取到锁了吗,那就可以理解为 state 等于 0 即是无锁的状态,下面将 state 的值修改为 acquires 就是获取到锁了,改变资源的状态:

在这里插入图片描述

接着如果 state 的值不是 0 ,则当前锁已经被别的线程持有了,这里又判断了下,如果持有锁的线程正好是当前的线程,那不就是锁的重入吗,这种情况下可以直接获得锁,不过这里为了记录重入的次数,对 state 共享资源进行了 + acquires 操作,其实就是 +1 操作。

在这里插入图片描述

如果都没有成功,那此时则获取锁失败,返回 false

2.3 FairSync下的 tryAcquire

FairSync 类下的 tryAcquire 方法中,和前面 NonfairSync 类似,但不同的是,在获取到锁时,也就是拿到 state 等于 0 ,进行修改资源时,多了步 hasQueuedPredecessors 的判断:

在这里插入图片描述

下面可以进到 hasQueuedPredecessors 的方法中,可以看到是由 AQS 提供的方法,主要就是判断当前节点线程的前面是否还有等待的线程,因为 FairSync 实现的是公平锁的原则,如果当前线程前面还有等待线程,则获取锁资源也轮不到自个,让前面的老大先来:

在这里插入图片描述
hasQueuedPredecessors 方法理解后,其余的逻辑则和 NonfairSync 中的一致了。

2.4 tryRelease

到这里已经了解到了tryAcquire 尝试获取资源的逻辑,上面提到了两个重要方法,还有一个 tryRelease 没有分析逻辑,还是首先看 Sync 类中是否有重写该方法:

通过源码可以看到,在 Sync 类中就已经对 tryRelease 进行了重写,而 NonfairSyncFairSync 中都没有重写该方法,那释放资源就是走的 Sync 类下的 tryRelease 方法:
在这里插入图片描述

在该方法中,可以看到首先还是获取到了 AQS 中的 state 共享资源,然后对该资源进行 - releases (默认releases1,下面会提到 )操作,其实就是 -1 操作:

在这里插入图片描述
接着判断了下,如果当前线程不是持有锁线程,就抛出异常,也好理解,没有持有锁的线程跑过来释放锁,那肯定有问题了呀。

接着再进行判断 state 是不是等于 0 ,上面讲到在锁重入的情况下,记录重入的次数是对 state 进行 +1 操作,而这边又对 state 进行 -1 操作,如果减到最后 state 有成了最初的 0 ,那不就是重入的锁和当前持有的锁都释放完了吗,这个时候就可以将持有锁的线程置为空了,并修改最新的 state

在这里插入图片描述

看到这里就会发现获取锁和释放锁,无非就是对 AQS 中的共享资源进行操作。理解了这两大核心的方法后,下面就可以看如何运用在 ReentrantLock 中的了。

三、lock.lock()

ReentrantLock 中,需要获取锁时,直接使用 lock.lock() 即可,那 lock.lock() 到底做了什么呢,点到该方法中,可以看到是调用的 Synclock 方法,而 Sync 中的lock 方法是抽象方法,具体实现肯定在子类的 NonfairSync、 FairSync 中。

在这里插入图片描述

3.1 NonfairSync.lock()

首先看点 NonfairSync 非公平锁中的 lock 方法,直接进行了将 AQS 中的共享资源 state0 改为 1 ,如果修改成功,根据上面分析的结论不就是获取锁成功了吗,可以将AQS中的独占线程设为自己了。但是如果其他线程修改成功了,这里使用 CAS 就会修改失败,因此就会进到 acquire 方法,注意这里传递的参数默认就是 1 ,对应着前面括号中的说明:

在这里插入图片描述

acquire 方法,就是 AQS 中的独占模式获取同步资源的逻辑,会调用当前方法的 tryAcquire 尝试获取资源,如果获取不到,则加入到 AQS 的阻塞队列并阻塞挂起线程。

在这里插入图片描述

关于acquire 方法的源码解读可以参考文章开始的链接中对 AQS 源码的解读。

3.2 FairSync.lock()

FairSync 公平锁中,由于需要遵循先进先出的原则,这里没有直接已粗暴的形式对 state 进行修改,而是直接调用了 AQS 中的 acquire 方法,而 acquire 方法又会调用当前类的 tryAcquire 获取资源。

但在当前类的 tryAcquire 方法中,如果获取到了资源,会接着进行判断当前线程的前面是否还有等待的线程,如果有则让出来让别人获取资源,因此就遵循了公平锁的原则,注意这里传递的参数默认就是 1 ,同样对应着前面括号中的说明:

在这里插入图片描述
同样 tryAcquire 尝试获取资源,如果获取不到,则加入到 AQS 的阻塞队列并阻塞挂起线程。

四、lock.unlock()

上面了解到了 lock 的逻辑,既然上锁了肯定需要解锁,下面点到 unlock() 方法中,可以看到直接使用了 Syncrelease 方法释放资源,其实是 AQS 中的 release 方法,注意这里传递的参数默认就是 1 ,同样对应着前面括号中的说明:

在这里插入图片描述

AQSrelease 方法中,首先会调用 Sync 类的 tryRelease 释放资源,然后对已阻塞的线程进行唤醒:

在这里插入图片描述

关于release 方法的源码解读可以参考文章开始的链接中对 AQS 源码的解读。

五、总结

通过阅读 ReentrantLock 的源码可以发现,大量依赖于 AQS 中提供的方法,所以在阅读前一定要理解下 AQS 的作用和功能。

相关内容

热门资讯

安卓系统目前哪个最好,探索当前... 你有没有想过,手机里的安卓系统就像是一群各具特色的英雄,每个都有自己独特的技能和魅力。那么,问题来了...
安卓系统怎么把图标锁上,图标锁... 手机里的图标乱糟糟的,是不是也想给它们来个“小锁”,让它们乖乖待在原地呢?别急,今天就来教你怎么把安...
微软换账号注册安卓系统,安卓系... 你有没有想过,有一天你的安卓手机突然焕然一新,仿佛重获新生?这可不是普通的升级,而是因为微软的账号注...
怎么停止安卓系统更新,轻松关闭... 手机更新又来了!是不是每次安卓系统更新,你的手机都像被施了魔法,速度变慢,电池续航也跟着缩水?别急,...
股票买平板还是安卓系统,股票投... 最近是不是也被手机屏幕的诱惑给勾住了?想换一台新平板,但又纠结是买苹果的iPad还是安卓系统的平板呢...
iso系统比安卓安全,超越安卓... 你知道吗?在手机操作系统这个江湖里,ISO系统和安卓系统可是两大门派,各有所长。但今天,我要给你揭秘...
安卓手机系统排名图片,揭秘市场... 你有没有发现,现在安卓手机市场上,各种品牌的手机层出不穷,让人眼花缭乱?今天,就让我带你一起走进这个...
安卓系统手机没电图片,电量耗尽... 手机没电了,这可是个让人头疼的小麻烦呢!想象你正沉浸在追剧的乐趣中,突然屏幕一黑,手机没电了。这时候...
安卓系统温控模块在哪里,核心功... 你有没有遇到过手机发热的情况,是不是觉得手机就像个小暖炉,让你有点招架不住呢?别急,今天就来给你揭秘...
最流畅的安卓原生系统,探索安卓... 你有没有想过,为什么你的手机用起来有时候那么卡,有时候又那么流畅呢?这背后,其实隐藏着一个秘密——那...
安卓系统可以刷windows吗... 你有没有想过,你的安卓手机或者平板,竟然能变身成一台Windows电脑?是的,你没听错,安卓系统是可...
苹果安卓操作系统,全面对比与深... 你有没有想过,为什么你的手机里装了那么多应用,而别人的手机却看起来那么清爽?这背后,其实就是苹果的i...
安卓tv中文系统,功能解析与使... 你有没有发现,家里的安卓TV最近变得超级智能呢?没错,就是那个曾经只能看看视频、玩玩游戏的小家伙,现...
谷歌安卓10系统打不开,原因排... 最近是不是你也遇到了这个让人头疼的问题:谷歌安卓10系统打不开?别急,让我来帮你一步步排查,找出原因...
安卓系统转苹果吃鸡,体验全新i... 你知道吗?最近身边的小伙伴们都在热议一个话题:从安卓系统转到苹果手机,体验吃鸡游戏的新鲜感。这可不是...
双系统d盘安装安卓,轻松实现手... 你有没有想过,在电脑上同时拥有Windows系统和安卓系统,是不是就像拥有了两个世界的大门呢?想象一...
安卓系统后台运行程序,高效运行... 你有没有发现,手机里的安卓系统后台运行程序有时候就像那些调皮的小精灵,悄无声息地在你不知道的时候忙碌...
苹果ipad如何改安卓系统,轻... 你有没有想过,把你的苹果iPad换成安卓系统,是不是会有一种全新的使用体验呢?想象那些你熟悉的安卓应...
安卓隐藏系统状态栏,安卓隐藏系... 你有没有发现,手机屏幕下方那个小小的状态栏,有时候真的挺碍眼的?尤其是当你沉浸在游戏或者追剧的时候,...
bb10系统安装安卓,轻松实现... 你有没有想过,把那老式的BB10系统升级成安卓,让它焕发第二春呢?想象你的老手机瞬间变成了一个功能强...