ReentrantLock(重入锁)简单源码分析
1.ReentrantLock是基于AQS实现的一种重入锁。
2.先介绍下公平锁/非公平锁
公平锁
- 公平锁是指多个线程按照申请锁的顺序来获取锁。
非公平锁
- 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。
3.重入锁/不可重入锁
可重入锁:广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。
不可重入锁:不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。
4.统一入口
//获取锁。
@Override
public void lock() {
sync.lock();
} //获取锁,响应中断
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly();
} //仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
@Override
public boolean tryLock() {
return sync.nonfairTryAcquire();
} //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被 中断,则获取该锁。
@Override
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(, unit.toNanos(timeout));
} //试图释放此锁。
@Override
public void unlock() {
sync.release();
}
ReentrantLock默认是非公平模式,可以通过构造函数指定模式。
/**
* 构造函数,默认非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
} /**
* 构造函数,通过布尔参数设置是否是公平锁
* @param fair
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
4.非公平模式的加锁和解锁
加锁:
//获取锁。
@Override
public void lock() {
sync.lock();
}
然后调用NonfairSync的lock方法:
/**
* 加锁
*/
@Override
final void lock() {
//以cas方式尝试将AQS中的state从0更新为1
if (compareAndSetState(, )) {
//获取锁成功则将当前线程标记为持有锁的线程,然后直接返回
setExclusiveOwnerThread(Thread.currentThread());
} else {
acquire();
}
}
如果设置state失败,则调用NonfairSync的tryAcquire方法
@Override
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
然后调用Sync的nonfairTryAcquire方法:
/**
* 非公平模式的情况下获取同步状态
* @param acquires
* @return
*/
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程实例
final Thread current = Thread.currentThread();
//获取同步state变量的值,即当前锁被重入的次数
int c = getState();
//state为0,说明当前锁未被任何线程持有
if (c == ) {
//以cas方式获取锁
if (compareAndSetState(, acquires)) {
//将当前线程标记为持有锁的线程
setExclusiveOwnerThread(current);
//获取锁成功,非重入
return true;
}
//当前线程就是持有锁的线程,说明该锁被重入了,实现重入
} else if (current == getExclusiveOwnerThread()) {
//计算state变量要更新的值
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
//尝试获取锁失败
return false;
}
这边体现了锁的重入,用state的次数表示锁被线程重入了state次。
else if (current == getExclusiveOwnerThread()) {
//计算state变量要更新的值
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
解锁:
//试图释放此锁。
@Override
public void unlock() {
sync.release();
}
然后调用Sync的tryRelease方法:
/**
* 释放同步状态
* @param releases
* @return
*/
@Override
protected final boolean tryRelease(int releases) {
//计算待更新的state值
int c = getState() - releases;
//判断当前线程是否独占
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
//是否释放同步状态成功的标志
boolean free = false;
//待更新的state值为0,说明持有锁的线程未重入,一旦释放锁其他线程将能获取
if (c == ) {
free = true;
//清除锁的持有线程标记
setExclusiveOwnerThread(null);
}
//更新state值
setState(c);
return free;
}
5.公平模式的加锁和解锁
加锁:
@Override
protected final boolean tryAcquire(int acquires) {
//获取当前线程实例
final Thread current = Thread.currentThread();
//获取同步state变量的值,即当前锁被重入的次数
int c = getState();
//state为0,说明当前锁未被任何线程持有
if (c == ) {
/**
* 1.判断同步队列中当前节点是否有前驱节点
* 2. 以cas方式获取锁
*/
if (!hasQueuedPredecessors() &&
compareAndSetState(, acquires)) {
//将当前线程标记为持有锁的线程
setExclusiveOwnerThread(current);
return true;
}
//当前线程就是持有锁的线程,说明该锁被重入了,实现重入
} else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < )
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
//尝试获取锁失败
return false;
}
对于非公平锁,只要cas设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同,公平锁的获取增加了hasQueuedPredecessors的判断,即加入了判断同步队列中当前节点是否有前驱节点,
如果返回true,则表示有线程比当前线程更早滴请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。
解锁:同公平锁的解锁方式
ReentrantLock(重入锁)简单源码分析的更多相关文章
- ReentrantLock(重入锁)的源码解析
转自:从源码角度彻底理解ReentrantLock(重入锁)](https://www.cnblogs.com/takumicx/p/9402021.html)) 公平锁内部是FairSync,非公平 ...
- 从源码角度彻底理解ReentrantLock(重入锁)
目录 1.前言 2.AbstractQueuedSynchronizer介绍 2.1 AQS是构建同步组件的基础 2.2 AQS的内部结构(ReentrantLock的语境下) 3 非公平模式加锁流程 ...
- java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)
1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...
- ReentrantLock 锁释放源码分析
ReentrantLock 锁释放源码分析: 调用的是unlock 的方法: public void unlock() { sync.release(1); } 接下来分析release() 方法: ...
- java高并发系列 - 第12天JUC:ReentrantLock重入锁
java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...
- JUC之线程池基础与简单源码分析
线程池 定义和方法 线程池的工作时控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等待其他线程执行完成,再从队列中取出任 ...
- ReentrantLock(重入锁)以及公平性
ReentrantLock(重入锁)以及公平性 标签(空格分隔): java NIO 如果在绝对时间上,先对锁进行获取的请求一定被先满足,那么这个锁是公平的,反之,是不公平的,也就是说等待时间最长的线 ...
- ReentrantLock重入锁详解
1.定义 重入锁:能够支持一个线程对资源的重复加锁,也就是当一个线程获取到锁后,再次获取该锁时而不会被阻塞. 2.可重入锁的应用场景 2.1 如果已经加锁,则不再重复加锁,比如:交互界面点击后响应时间 ...
- Java多线程之ReentrantLock重入锁简介与使用教程
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543947.html 我们知道,线程安全问题需要通过线程之间的同步来解决,而同步大多使用syncrhoize ...
随机推荐
- python 修饰器 最好的讲解
Python的修饰器的英文名叫Decorator,修饰器就是对一个已有的模块做一些“修饰工作”,比如在现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能 ...
- Scrapy学习-11-Selector对象使用
Selector使用 使用背景 我需要使用类似spider项目中,response使用的xpath和css获取页面指定数据,但因为爬取页面较小我们不想创建一个spider项目时,就可以使用scrapy ...
- Codeforces 932 A.Palindromic Supersequence (ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined))
占坑,明天写,想把D补出来一起写.2/20/2018 11:17:00 PM ----------------------------------------------------------我是分 ...
- Codeforces Gym101606 D.Deranging Hat (2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017))
D Deranging Hat 这个题简直了,本来想的是冒泡排序然后逆着输出来的,后来发现不对,因为题目上求的是最优解,而且冒泡的话,输出结果有的超出10000行了,所以就是把一开始的,排好序的字母标 ...
- L1-3. 情人节【求第2个、第14个人的名字,设置计数器并标记一下即可】
L1-3. 情人节 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 以上是朋友圈中一奇葩贴:“2月14情人节了,我决定造福大家. ...
- 2017 ACM-ICPC 沈阳区域赛记录
出发日 中午坐大巴前往萧山机场. 哇开心又可以坐飞机了 飞机延误了.在候机大厅里十分无聊,先用机场的电脑玩了会小游戏 然后偷偷切了2个水题 (什么编译器IDE都没有,只能记事本了) 飞机上什么东西都没 ...
- 板子-GOD BLESS ALL OF YOU
字符串: KMP #include<cstdio> #include<cstring> ; ]; ]; int l1,l2; void get_next() { next[]= ...
- Hdoj 3506 Monkey Party
Discription Far away from our world, there is a banana forest. And many lovely monkeys live there. O ...
- BZOJ1005明明的烦恼 Prufer + 分解質因數 + 高精度
@[高精度, Prufer, 質因數分解] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多 ...
- javascript 对象初探 (四)--- 内建对象之旅之Boolean
var a = new Boolean() 我们要明白一点在这里的b是一个对象而不是一个基本数据类型的布尔值.如果想将b转化成基本数据类型的布尔值,我们可以调用她的valueof()方法(继承自Obj ...