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 的作用和功能。

相关内容

热门资讯

安卓4.4系统tv软件,探索安... 亲爱的读者们,你是否曾为家里的电视屏幕增添一些智能的魔力而烦恼?别担心,今天我要给你带来一个超级实用...
安卓系统的研究人物,安卓系统发... 你知道吗?在科技飞速发展的今天,安卓系统可是占据了智能手机市场的大半壁江山。而在这片广阔的天地里,有...
山寨苹果刷会安卓系统,安卓系统... 你知道吗?在科技圈里,总有一些让人眼前一亮的小秘密。今天,我要给你揭秘一个关于山寨苹果刷安卓系统的神...
安卓系统新用户登录,畅享智能生... 你刚刚入手了一台全新的安卓手机,是不是有点小激动呢?别急,别急,让我来给你详细介绍一下安卓系统新用户...
安卓8.0系统推荐版本,体验流... 你有没有发现,手机系统更新换代的速度简直就像小孩子的成长一样快?这不,安卓8.0系统已经悄悄地来到了...
安卓系统怎么分享位置吗,一键操... 你是不是也有过这样的经历:和朋友约好见面,却因为找不到对方而急得团团转?别担心,今天就来教你怎么在安...
安卓系统更新加速器,畅享极速升... 你有没有发现,手机更新系统的时候总是慢吞吞的,让人等得心痒痒?别急,今天就来给你安利一款神器——安卓...
百答系统和安卓系统区别,差异解... 你有没有想过,为什么你的手机里装了那么多应用,却还是觉得信息不够全面?其实,这背后的大脑——操作系统...
安卓锁系统设置软件,软件设置与... 手机里的秘密可多了去了,是不是有时候你也会觉得,这手机里的信息要是被别人看到了可怎么办呢?别担心,今...
安卓电视u盘游戏系统,轻松畅享... 你有没有想过,家里的安卓电视也能玩上那些刺激的电脑游戏呢?没错,就是那种让你一玩就停不下来的游戏!今...
挂载安卓系统为读写权限,读写权... 你有没有想过,你的手机里那些神奇的安卓系统,竟然可以赋予某些应用读写权限?这听起来是不是有点像科幻电...
安卓12系统怎么打补丁,保障设... 亲爱的安卓用户们,你是否也遇到了系统卡顿、bug频发的小烦恼呢?别急,今天就来给你支个招——安卓12...
客厅电脑用安卓系统好吗,体验智... 亲爱的读者,你是不是在为客厅电脑选择操作系统而烦恼呢?安卓系统,这个我们日常手机上常见的操作系统,是...
安卓系统能看访客记录,轻松查看... 你有没有想过,你的安卓手机里藏着一个小秘密?没错,就是访客记录!是的,你没听错,你的手机里竟然能查看...
印度安卓系统电脑推荐,性能卓越... 你有没有想过,在印度这片神奇的土地上,用一台安卓系统电脑会是怎样的体验呢?想象阳光洒在泰姬陵的白色大...
安卓系统合作公司,安卓系统合作... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅拥有庞大的用户群体,还吸引了一大批合作公司...
苹果表有安卓系统时间,时间同步... 你有没有发现,最近苹果表也开始支持安卓系统了?没错,就是那个一直以封闭著称的苹果,竟然也开始拥抱安卓...
原生安卓系统裁剪图片,原生安卓... 你有没有发现,用原生安卓系统拍照,有时候拍出来的照片分辨率超高,但就是有点大,想裁剪却不知道怎么操作...
安卓系统蓝牙开关APP,安卓系... 你有没有遇到过这种情况:手机里的安卓系统蓝牙开关总是让人摸不着头脑?有时候想开蓝牙,却找不到开关在哪...
安卓系统能登录ios系统王者吗... 你有没有想过,安卓系的手机能不能登录iOS系统的王者荣耀呢?这可是个让人好奇不已的问题哦!毕竟,两个...