并发——深入分析ReentrantLock的实现原理
1|0一、前言
之前花了点时间研究了一下并发包下的一个重要组件——抽象队列同步器AQS
,在并发包中,很多的类都是基于它实现的,包括Java
中常用的锁ReentrantLock
。知晓了AQS
的实现原理,那理解ReentrantLock
的实现就非常简单了,因为它的锁功能的实现就是由AQS
实现的,而它的工作仅仅是重写了一些AQS
中的相关方法,并使用其中的模板方法进行加锁解锁。今天这篇博客就来从源码的角度分析一下ReentrantLock
的实现。
2|0二、正文
2|12.1 抽象队列同步器AQS
在说ReentrantLock
前,必须要先提一下AQS
。AQS
全称抽象队列同步器(AbstractQuenedSynchronizer),它是一个可以用来实现线程同步的基础框架。当然,它不是我们理解的Spring
这种框架,它是一个类,类名就是AbstractQuenedSynchronizer
,如果我们想要实现一个能够完成线程同步的锁或者类似的同步组件,就可以在使用AQS
来实现,因为它封装了线程同步的方式,我们在自己的类中使用它,就可以很方便的实现一个我们自己的锁。
AQS
的实现相对复杂,无法通过短短的几句话将其说清楚,我之前专门写过一篇分析AQS
实现原理的博客:并发——抽象队列同步器AQS的实现原理。
在阅读下面的内容前,请一定要先学习AQS的实现原理,因为ReentrantLock
的实现非常简单,完全就是依赖于AQS
的,所以我以下的描述均建立在已经理解AQS
的基础之上。可以阅读上面推荐博客,也可以自己去查阅相关资料。
2|22.2 ReentrantLock的实现原理
我们先简单介绍一下ReentrantLock
的实现原理,这样方便我们下面阅读它的源码。前面也说过,ReentrantLock
基于AQS
实现,AQS
的模板方法acquire
,release
等,已经实现了加锁和解锁的操作,而使用它的类只需要重写这些模板方法中调用的方法,比如tryAcquire
,tryRelease
等,这些方法通过修改AQS
的同步状态state
来加锁解锁。AQS
的同步状态state
是一个int
类型的值,根据不同的值,就可以判断当前锁的状态,同时修改这个值就是加锁和解锁的方式。
使用AQS
的一般方式是以内部类的形式继承AQS
,ReentrantLock
也是这么实现的,在它的内部,有三个AQS
的派生类:
- 首先第一个派生类名字叫做Sync,这是一个抽象类,直接继承自
AQS
,其中定义了一些通用的方法; - 第二个派生类名字叫做NonfairSync,它继承自
Sync
,实现的是一种非公平锁; - 第三个派生类名字叫FairSync,它也继承自
Sync
,实现的是一种公平锁;
ReentrantLock
就是通过NonfairSync
对象或者FairSync
对象来保证进行线程同步的。而这三个类中编写的方法,实际上就是修改同步状态的方式。当state
的值为0
时,表示当前并没有线程获取锁,而每获取一次锁,state
的值就会+1
,释放一次锁,state
就-1
。下面我们就通过这三个类的源码来具体看一看吧。
2|32.3 Sync类源码解析
我们直接来看看Sync
类中的方法吧,Sync类中的方法不少,我只拿出其中比较重要的几个来讲一讲:
以上就是Sync
类的实现。其实Sync
中的方法不仅仅只有上面这几个,但是剩下的那些方法都是一些零零碎碎,对我们理解ReentrantLock
没有太大帮助的方法,所以这里就不一一列举了。从上面的方法实现中,我们可以知道以下信息:线程获取锁的方式实际上就是让同步状态state的值增加,而释放锁的方式就是让state的值减小;而且ReentrantLock实现的是可重入锁,已经获取锁的线程可以不受阻碍地再次获取锁,state的值可以不断增加,而释放锁时,只有state的值减小为0,锁才是真正被释放。
2|42.4 NonfairSync类源码解析
下面我们再看看第二个内部类NonfairSync
,它实现的是非公平锁。
上面就是NonfairSync
类完整的代码,并没有删减,可以看出,非常的简短。实现了Sync
类中定义的lock
方法,同时重写了tryAcquire
方法,供AQS
的模板方法acquire
调用,且tryAcquire
的实现仅仅是调用了Sync
中的nonfairTryAcquire
方法。为了有助于我们理解,我们还是来看看AQS
中acquire
方法的代码吧:
为什么说NonfairSync
是非公平锁?我们可以看到,在NonfairSync
的lock
方法中,一个线程尝试去获取锁前,并不会判断在它之前是否有线程正在等待获取锁,而是直接尝试调用compareAndSetState
方法获取一次锁,若获取失败,进入acquire
方法,在这个方法中又会调用tryAcquire
方法获取一次锁。此时若再次获取失败,才会进行进入同步队列中排队,这个过程中插了两次队,所以NonfairSync
是非公平锁。
2|52.5 FairSync类源码解析
下面我们来看看最后一个内部类FairSync
,它实现的是公平锁,也就是线程按照先来后到的顺序获取锁,而不会插队:
FairSync
的实现也比较简单。值得注意的是,因为FairSync实现的是公平锁,所以线程获取锁前,会先判断是否有在它之前尝试获取锁的线程在排队,若有,则当前线程不能插队,也需要进行排队,并且排在那些线程之后。
2|62.6 ReentrantLock的成员属性与构造方法
看完了内部类,下面就正式来看一看ReentrantLock
是如何操作的吧,首先看一看它的成员属性和构造方法构造方法:
2|72.7 ReentrantLock的加锁与解锁
下面我就来看看ReentrantLock
最重要的两个操作,加锁和解锁。
(1)获取锁的方法实现
(2)是否锁的方法实现
以上就是ReentrantLock
加锁和解锁的方法,出乎意料,非常的简单,每个方法都只有一句代码,调用AQS
类中提供的模板方法。这就是AQS
的好处,AQS
封装了线程同步的代码,我们只需要在类中使用它,就能很简单的实现一个锁。所以我前面才说,在看ReentrantLock
前,一定要先学习AQS
,理解了AQS
,理解ReentrantLock
就完全没有难度了。
上面这些就是ReentrantLock
中的关键方法,其实除了这些方法之外,还有许多其他的方法,但是那些方法并不是关键,实现也都非常简单,基本上就是一句代码,可以自己直接去阅读源码,我这里就不一一列举了。
3|0三、总结
经过上面的分析,我们会发现,ReentrantLock
的实现原理非常的简单,因为它是基于AQS
实现的,复杂性都被封装在了AQS
中,ReentrantLock
仅仅是它的使用者,所以,学习ReentrantLock
实际上就是学习AQS
。AQS
是Java
并发中的重要组件,很多的类都是基于它实现的,比如非常常用的CountDownLatch
。AQS
也是面试中的常考题,所以一定要好好研究。此处再次推荐我写的AQS
解析博客:并发——抽象队列同步器AQS的实现原理。
4|0四、参考
- JDK1.8源码
__EOF__

本文链接:https://www.cnblogs.com/tuyang1129/p/12689122.html
关于博主:在互联网洋流中垂死挣扎,但依旧乐观的Java小菜鸟一枚!
版权声明:转载博客请注明出处,并附上原文链接!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构