ReentrantLock源码解析

ReentrantLock源码解析

文章目录

  • ReentrantLock源码解析
    • 一、ReentrantLock
    • 二、ReentrantLock 的 Sync、FairSync、NonfairSync
      • 2.1 Sync、FairSync、NonfairSync
      • 2.2 NonfairSync 下的 tryAcquire
      • 2.3 FairSync下的 tryAcquire
      • 2.4 tryRelease
    • 三、lock.lock()
      • 3.1 NonfairSync.lock()
      • 3.2 FairSync.lock()
    • 四、lock.unlock()
    • 五、总结

一、ReentrantLock

ReentrantLock 是 Java JUC 中的一个可重入锁,ReentrantLock锁 是基于 AQS 实现的。

在 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源码解析 这篇文章

下面开始 ReentrantLock 源码的分析:

二、ReentrantLock 的 Sync、FairSync、NonfairSync

2.1 Sync、FairSync、NonfairSync

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

  • new ReentrantLock();
  • new ReentrantLock(false);

当使用无参构造函数声明时,则是创建了一个 NonfairSync 对象:
在这里插入图片描述

通过有参的构造函数,则根据传入的 fair 可以选择创建一个 FairSync 对象:
在这里插入图片描述

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

点到这两个类中,可以看到都继承自 Sync 类:
在这里插入图片描述

而 Sync 类,则继承了 AQS :
在这里插入图片描述

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

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

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

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

2.2 NonfairSync 下的 tryAcquire

首先看下 NonfairSync 的 tryAcquire() 实现逻辑,可以看到又调用了 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() 进行了重写,而 NonfairSync 和 FairSync 中都没有重写该方法,那释放资源就是走的 Sync 类下的 tryRelease() 方法:
在这里插入图片描述

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

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

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

在这里插入图片描述

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

三、lock.lock()

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

在这里插入图片描述

3.1 NonfairSync.lock()

首先点进 NonfairSync 非公平锁中的 lock() 方法,直接进行了将 AQS 中的共享资源 state 由 0 改为 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() 方法中,可以看到直接使用了 Sync 的 release() 方法释放资源,其实是 AQS 中的 release() 方法,注意这里传递的参数默认就是 1,同样对应着前面括号中的说明:
在这里插入图片描述

在 AQS 的 release() 方法中,首先会调用 Sync 类的 tryRelease() 释放资源,然后对已阻塞的线程进行唤醒:
在这里插入图片描述

关于 release() 方法的源码解析可查看 AQS源码解析 。

五、总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/165063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优橙内推青海专场——5G网络优化(中高级)工程师

可加入就业QQ群:801549240 联系老师内推简历投递邮箱:hrictyc.com 内推公司1:浙江明讯网络技术有限公司 内推公司2:南京华苏科技有限公司 内推公司3:杭州华星创业通信技术有限公司 浙江明讯网络技术有限公司 浙江明…

4.常见面试题--操作系统

特点:并发性、共享性、虚拟性、异步性。 Windows 和 Linux 内核差异 对于内核的架构⼀般有这三种类型: ● 宏内核,包含多个模块,整个内核像⼀个完整的程序; ● 微内核,有⼀个最⼩版本的内核&#xff0…

名字大却不中用的AI大模型,名不副实

这两天 OpenAI 团队( ChatGPT 公司)的戏比较多,两三天的功夫,剧情发展都超出了 OpenAI 首席科学家的预期,目前来看,微软还是最大的赢家。这是个引子,这个话题,网络上早已传烂了&…

云安全之盾:ZStack 云主机安全防护解决方案全方位保护云环境

随着云计算的蓬勃发展,网络威胁愈发复杂,涵盖了从勒索病毒到APT攻击的各种威胁类型。在这一风云变幻的网络安全环境下,云主机安全不再仅仅是一个选项,它是信息系统安全的核心要素。云轴科技ZStack 云主机安全防护解决方案是为了满…

6.3.WebRTC中的SDP类的结构

在上节课中呢,我向你介绍了sdp协议, 那这节课呢,我们再来看看web rtc中。是如何存储sdp的?也就是sdp的类结构,那在此之前呢?我们先对sdp的内容啊,做一下分类。因为在上节课中呢,虽然…

Python+jieba+wordcloud实现文本分词、词频统计、条形图绘制及不同主题的词云图绘制

目录 序言:第三方库及所需材料函数模块介绍分词词频统计条形图绘制词云绘制主函数 效果预览全部代码 序言:第三方库及所需材料 编程语言:Python3.9。 编程环境:Anaconda3,Spyder5。 使用到的主要第三方库:…

python之pyqt专栏1-环境搭建

#python pyqt# python:3.11.6 pycharm:PyCharm Community Edition 2023.2.5 pyqt6 python安装 官网下载:Python Releases for Windows | Python.org pycharm社区版安装 官网地址:Download PyCharm: Python IDE for Professional…

golang学习笔记——创建项目

创建项目 从Go 1.8开始,将GOPATH设置为环境变量不是必需的。如果我们没有设置一个,Go使用默认的GOPATH为$HOME/go。可以使用go env查看环境变量信息。 创建项目 # 创建项目目录 mkdir helloLog cd helloLog # 使用go mod初始化项目,生成go.mod文件 go…

TikTok shop印尼重启电商征程:与当地平台合作开启新篇章!——站斧浏览器

经历了一个半月的间隔,TikTok Shop成功重返印度尼西亚市场。据国际媒体报道,TikTok计划通过与印尼本地电子商务平台的合作,重启其在该国的电商业务。 Temmy Satya Permana,印尼合作社和中小企业部的官员,证实了这一重…

【广州华锐互动】VR线上课件制作软件满足数字化教学需求

随着科技的不断发展,虚拟现实(VR)技术在教学领域的应用逐渐成为趋势。其中,广州华锐互动开发的VR线上课件制作软件更是备受关注。这种工具为教师提供了便捷的制作VR课件的手段,使得VR教学成为可能,极大地丰…

thinkphp6 不支持:redis错误

起因: 使用 redis 时候,thinkphp 报错。 解决方法: 打开 php.ini 文件,增加 extensionphp_redis.dll 即可

Java架构师发展方向和历程

目录 1 导论2 架构师的三观培养3 架构师的遇到的困难4 架构师职责5 架构师之路6 架构师的发展方向7 应用领域架构师8 业务架构师9 系统架构师和企业架构师10 技术路线和演进规划11 一线大厂的技术生态拓张案例12 如何推进项目落地想学习架构师构建流程请跳转:Java架构师系统架…

CUDA与GPU编程

文章目录 CUDA与GPU编程1. 并行处理与GPU体系架构1.1 并行处理简介1.1.1 串行处理与并行处理的区别1.1.2 并行处理的概念1.1.3 常见的并行处理 1.2 GPU并行处理1.2.1 GPU与CPU并行处理的异同1.2.2 CPU的优化方式1.2.3 GPU的特点 1.3 环境搭建 CUDA与GPU编程 1. 并行处理与GPU体…

城市管理实景三维:打造智慧城市的新引擎

城市管理实景三维:打造智慧城市的新引擎 在城市管理领域,实景三维技术正逐渐成为推动城市发展的新引擎。通过以精准的数字模型呈现城市真实场景,实景三维技术为城市决策提供了全新的思路和工具。从规划设计到交通管理,从环境保护到…

嵌入式系统在工业自动化中的应用

嵌入式系统在工业自动化中的应用非常广泛,它们通过集成控制和实时响应能力,实现了生产线的自动化、智能化和高效化。以下将详细介绍嵌入式系统在工业自动化中的几个重要应用领域,并提供一些示例代码。 1. PLC(可编程逻辑控制器&a…

【开源】基于Vue和SpringBoot的学校热点新闻推送系统

项目编号: S 047 ,文末获取源码。 \color{red}{项目编号:S047,文末获取源码。} 项目编号:S047,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 新闻类型模块2.2 新闻档案模块2.3 新…

Python模块之yaml:简化配置与数据解析

更多Python学习内容:ipengtao.com YAML(YAML Aint Markup Language)是一种人类可读的数据序列化格式,常用于配置文件和数据传输。在Python中,可以使用PyYAML模块来处理YAML格式的数据。本文将深入介绍PyYAML的基础用法…

力扣H指数——简约做法

Problem: 274. H 指数 文章目录 思路解题方法复杂度Code 思路 最后的结果一定不会超过下标个数。应为文章也要大于这个h,h超过了文章总数,就永远不会存在这么多的文章满足条件,所以只需要循环下标,那么最后的结果呢? 解…

AI质差小区优化效果评估

1. 下行流量/PRB利用率和贬损用户的关系 通过分析长期贬损质差小区:下行PRB利用率/流量和小区平均每小时质差用户数成正比例关系,即小区的贬损用户会随PRB利用率/流量的增长而增长。 2. 贬损用户和流量走势 年前平均每天流量平稳的情况下,通…

关于JS stack trace解决办法

问题描述 npm run serve启动前端项目时&#xff0c;控制台输出下图一堆的文字&#xff0c;JS stack trace , 问题现象&#xff1a; JS stack trace Security context: 0000017B93ACFB61 <JS Object>1: init_scope_vars [0000017B93A04381 <undefined>:~3382] [p…