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 ...
随机推荐
- bootstrapTable 应用小例(收索)
<script src="/plugins/My97DatePicker/WdatePicker.js"></script> <!-- Content ...
- 大视野 1016: [JSOI2008]最小生成树计数(最小生成树)
总结:此类题需要耐心观察规律,大胆猜想,然后证明猜想,得到有用的性质,然后解答. 简单的说:找隐含性质. 传送门:http://61.187.179.132/JudgeOnline/problem.p ...
- HRBUST 2072:萌萌哒十五酱的礼物~(树,字典树)
题意:n个点的一棵树,树的边上有权值.一条路径的权值定义成这条路径上所有边的权值的xor.问所有路径的最大权值是多少. 思路: 首先,树上任意两点之间的路可以表示成 这两点到根节点的路- 其最近公共祖 ...
- DBGridEH如何去表头?设置哪个属性
- Scrollview总结:滑动问题、监听Scrollview实现头部局改变
ScrollView就是一个可以滚动的View,这个滚动的方向是垂直方向的,而HorizontalScrollView则是一个水平方向的可以滚动的View. ScrollView的简单介绍 Scrol ...
- Javascript 评估用户输入密码的强度
什么是一个安全的密码呢? 1.如果密码少于5位,那么就认为这是一个弱密码. 2.如果密码只由数字.小写字母.大写字母或其它特殊符号当中的一种组成,则认为这是一个弱密码. 3.如果密码由数字.小写字母. ...
- Java开发者使用C++写程序踩的坑
笔者是一个很矛盾的人.平时用Java.但是一开始学习的时候学的是汇编语言,而且对C语言也很熟悉.为什么不学C++呢?是因为我可以完全用Java的编码规范去写C++.因此我不需要了解更多的诸如C++的命 ...
- Java RandomAccessFile类
RandomAccessFile类是Java中操作文件内容功能最强大的类,既可以读,也可以写. RandomAccessFile支持随机访问,可以直接访问文件的任意位置,在文件的任意位置读写数据.如果 ...
- BT服务器的搭建(tracker-P2P服务器架设)(转)
文章虽然有点老,但原理差不多. 继上一篇文章(http://www.cnblogs.com/EasonJim/p/6601146.html)介绍了BT的原理,现在来看下BT服务端搭建的原理. 一.BT ...
- Linux下查看某个命令的参数
1.一般每个命令都带有help参数,使用方法如下: shutdown --help 提示:shutdown为关机命令,在真实环境使用时需要root权限,比如前面加sudo. 2.使用man命令查看,使 ...