ReentrantLock之非公平锁源码分析
本文分析的ReentrantLock所对应的Java版本为JDK8。
在阅读本文前,读者应该知道什么是CAS、自旋。
由于ReentrantLock的公平锁和非公平锁中有许多共同代码,本文只会对这两种锁的不同之处加以分析,所以如果读者对公平锁不熟的话,强烈建议先看我的上篇博客——ReentrantLock之公平锁源码分析。
本文大纲
1.ReentrantLock非公平锁简介
2.lock方法
3.unlock方法
4.公平锁与非公平锁的异同
1. ReentrantLock非公平锁简介
ReentrantLock是JUC(java.util.concurrent)包中Lock接口的一个实现类,它是基于AbstractQueuedSynchronizer(下文简称AQS)来实现锁的功能。ReentrantLock的内部类Sync继承了AbstractQueuedSynchronizer,Sync又有FairSync和NonFairSync两个子类。FairSync实现了公平锁相关的操作,NonFairSync实现了非公平锁相关的操作。它们之间的关系如下:
非公平锁的不公平之处主要体现在,对于一个新来的线程,它会直接去抢占锁,不理会锁是否已经被占用或者该锁的等待队列中已经有其它的等待线程,如果抢占失败再进入等待队列队尾。
下面这段代码展示了非公平锁的使用方法:
private final Lock lock = new ReentrantLock(); // 调用ReentrantLock的空参构造方法,默认创建非公平锁 public void method() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock();
}
}
2. lock方法
ReentrantLock的lock方法调用了NonFairSync的lock方法:
public void lock() {
sync.lock();
}
NonFairSync的lock方法:
final void lock() {
if (compareAndSetState(0, 1)) // 注意!!!在非公平锁中,会先用CAS的方式去尝试更改锁的状态,即尝试去获取锁,不管锁是否被其他线程持有,也不理会等待队列中是否有等待的线程
setExclusiveOwnerThread(Thread.currentThread()); // 获取锁成功,则将当前占有锁的线程设置为当前线程
else
acquire(1); // CAS获取锁失败,则进入acquire方法
}
acquire方法:
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 这里将调用NonfairSync的tryAcquire方法
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 如果获取锁失败,执行acquireQueued方法,将把当前线程排入队尾
selfInterrupt();
}
tryAcquire方法:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
nonfairTryAcquire方法:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 获取锁的状态
if (c == 0) { // 如果状态是0,表示锁没有被占用
if (compareAndSetState(0, acquires)) { // 注意!!!在非公平锁中,这里不会判断队列中是否有等待的线程,非公平锁会直接去抢占锁
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
请注意上文的代码注释中有两个“注意!!!”,这两处就是公平锁和非公平锁的区别所在。
lock方法中,其它剩余的代码就和公平锁中的一样了,如果读者还需了解lock方法中后面的代码,请参见我的上篇博客。
3. unlock方法
和公平锁的unlock方法一样,请允许我偷个懒~ 还是参见我的上篇博客吧。
4. 公平锁与非公平锁的异同
- 在公平锁(FairSync)的lock方法中,会直接调用aquire方法;但是在非公平锁(NonfairSync)的lock方法中,会先采用CAS的方式去获取锁,不管是否有其他线程已经占有锁或者是否有其他线程在等待队列中。
- 公平锁(FairSync)调用的tryAcquire方法中,会先去检查等待队列中是否有等待的线程;但是在非公平锁(NonfairSync)调用的nonfairTryAcquire不会去检查等待队列。
- 无论公平锁还是非公平锁,对于排队中的线程,都能保证排在前面的线程一定比排在后面的线程优先获得锁。
ReentrantLock之非公平锁源码分析的更多相关文章
- ReentrantLock 的公平锁源码分析
ReentrantLock 源码分析 以公平锁源码解析为例: 1:数据结构: 维护Sync 对象的引用: private final Sync sync; Sync对象继承 AQS, Syn ...
- ReentrantLock之公平锁源码分析
本文分析的ReentrantLock所对应的Java版本为JDK8. 在阅读本文前,读者应该知道什么是CAS.自旋. 本文大纲 1.ReentrantLock公平锁简介 2.AQS 3.lock方法 ...
- 基于ReentrantLock的非公平锁理解AQS
AQS AQS概述 AbstractQueuedSynchronizer抽象队列同步器简称AQS,它是实现同步器的基础组件,juc下面Lock的实现以及一些并发工具类就是通过AQS来实现的,这里我 ...
- Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析
原文:Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析 一.RedissonLock#lock 源码分析 1.根据锁key计算出 slot,一个slot对 ...
- 从ReentrantLock实现非公平锁的源码理解AQS中的CLH队列
虽然前面也看过AQS的文章,并且转载过一篇大佬的分析,但是我觉得他们对于AQS和ReentrantLock部分的源码的分析并不详细,自己理解期来还是有问题,于是自己准备花时间重新梳理下,好了,进入正题 ...
- ReentrantLock锁 源码分析
根据下面代码分析下ReentrantLock 获得锁和释放锁的过程 ReentrantLock lock = new ReentrantLock(); lock.lock();//获得锁 lock.u ...
- ReentrantLock可重入锁——源码详解
开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...
- RedissonLock分布式锁源码分析
最近碰到的一个问题,Java代码中写了一个定时器,分布式部署的时候,多台同时执行的话就会出现重复的数据,为了避免这种情况,之前是通过在配置文件里写上可以执行这段代码的IP,代码中判断如果跟这个IP相等 ...
- ReentrantLock 公平锁源码 第0篇
ReentrantLock 0 关于ReentrantLock的文章其实写过的,但当时写的感觉不是太好,就给删了,那为啥又要再写一遍呢 最近闲着没事想自己写个锁,然后整了几天出来后不是跑丢线程就是和没 ...
随机推荐
- Linq小整理
Linq(Language Integrated Query)中文翻译为语言集成查询 (1)源起 .net的设计者在类库中定义了一系列的扩展方法 来方便用户操作集合对象 这些扩展方法构成了LINQ的查 ...
- python的统一编码规范
请注意这一点:没有编码规范的代码没有阅读价值,也更谈不上复用. 目前业界比较流行的Python的编码规范目前主要有PEP8的编程.Google的编码风格.Python Guide和Pocoo Styl ...
- C++ 文件流的详解
部分内容转载:http://blog.csdn.net/kingstar158/article/details/6859379 感谢追求执着,原本想自己写,却发现了这么明白的文章. C++文件流操作是 ...
- 2014金山笔试_编写一个数组类 MyVector
//编写一个数组类 MyVector,数组内容可以动态扩充,实现构造,析构,赋值操作符重载,插入,删除,获取元素个数,获取数组容量(不可以使用STL等的容器类,不能使用 //不连续的存储空间) #in ...
- CSS的浮动和定位
一.CSS中的浮动 1.定义和用法 float 属性定义元素在哪个方向浮动.在 CSS 中,任何元素都可以浮动.浮动会使原元素变成一个行级元素,而不论它本身是何种元素.如果浮动非替换元素,则要指定一个 ...
- spring boot之从零开始开发自己的网站
概述 首先要感谢两位大神,该项目的想法来源自tale和MyBlog,本项目的想法. 做了一些改造,增加了一些功能和一些代码的重构,并且更换了博客主题. 关于项目,对于开发的练手项目,能够工程化,严谨一 ...
- mysql workbench EER图,里面的实线以及虚线的关系
ERWin里面线代表实体间的三种关系:决定关系(Identifying Relationship),非决定关系(None-Identifying Relationship),多对多(Many-To-M ...
- git - 简明指南
助你入门 git 的简明指南,木有高深内容 ;) 作者:罗杰·杜德勒 感谢:@tfnico, @fhd 和 Namics如有纰漏,请在 github 提报问题 安装 下载 git OSX 版 下载 g ...
- FLASK 使用方法
Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档,大部分代码引用自官方文档. 安装Flask 首先我们来安装F ...
- 二十四、Hadoop学记笔记————Spark的架构
master为主节点 一个集群中可能运行多个application,因此也可能会有多个driver DAG Scheduler就是讲RDD Graph拆分成一个个stage 一个Task对应一个Spa ...