ReentrantLock-源码解析
ReentrantLock类注释
1、可重入互斥锁,意思是表示该锁能够支持一个线程对资源的重复加锁,该锁还支持获取锁的公平和非公平性选择。synchronized关键字隐式的支持重进入。
2、可以通过isHeldByCurrentThread
判断当前线程是否拿到锁。
3、构造器接收fairness参数,fairness=true表示公平锁反之是非公平锁。
4、tryLock() 无参方法没有遵循公平性,是非公平的。
5、公平锁的吞吐量没有非公平锁高,需要不断的进行线程之间的切换
ReentrantLock类结构
public class ReentrantLock implements Lock, java.io.Serializable
Lock所定义的方法。
- lock():获取锁,调用该方法的线程会获取锁。
- unlock(): 释放锁
- tryLock(): 尝试非阻塞的获取锁,获取成功返回true,失败返回false。
- tryLock(long,TimeUtil): 超时获取锁,有三种情况:当前线程在超时时间内获得了锁,当前线程在超时时间内被中断,超时时间结束,返回false。
- lockInterruptedException(): 可中断的获取锁,所在获取过程中可以中断当前线程。
公平锁与非公平锁
简言之,如果在绝对的时间上,先对锁发起请求的那个线程会先获取锁,遵循FIFO原则,也就是等待时间最长的那个线程最先获取锁。
公平锁和非公平锁只是相对于获取锁的时候而言。
如果一个锁是公平的,那么锁获取的顺序符合时间顺序。当一个线程获取了同步状态就可以认为获取到了锁,刚释放锁的线程下次再获取锁的概率非常大,使其他线程在同步队列中等待,因此非公平锁的线程切换次数很少,这是相对公平锁而言,所以吞吐量上,非公平锁更有优势,所以默认情况下,ReentrantLock的构造就是非公平锁。
互斥锁
互斥锁:同一时刻下,只有一个线程可以拿到锁,其他线程只能在同步队列中等待,只有拿到锁的线程释放锁,其他线程才能去争抢;
构造方法
public ReentrantLock() {
// 默认是非公平锁
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
从构造器中可以看出,公平锁是依靠 FairSync 实现的,非公平锁是依靠 NonfairSync 实现的。
Sync同步器
Sync继承了AQS,lock方法留给FairSync和NonFairSync两个子类实现,他实现了AQS的tryRelease方法和isHeldExclusively方法。
abstract static class Sync extends AbstractQueuedSynchronizer{
// 尝试释放锁
protected final boolean tryRelease(int releases) {
// releases一般是1,当前线程的同步状态-同步值
int c = getState() - releases;
// 当前线程没有持有锁,抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 当前线程持有的锁都释放了
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// c!=0代表是重入锁,锁没有释放完毕,前面已经用state-releases
setState(c);
return free; // return false,尝试释放锁失败
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
}
加锁
先来看FairSync公平锁的lock方法和tryAcquire
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
// 尝试加锁,acquire方法是AQS的获取锁的方法,如果尝试获取锁失败,会进入同步队列中等待
final void lock() {
acquire(1);
}
/**
AQS的acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
**/
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// hasQueuedPredecessors 是实现公平的关键
// 会判断当前线程是不是属于同步队列的头节点的下一个节点(头节点是释放锁的节点)
// 如果是(返回false),符合先进先出的原则,可以获得锁
// 如果不是(返回true),则继续等待
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 如果获取锁的线程再次请求锁,将通天阁不状态值增加并返回true,表示获取同步状态成功
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
再来看NonFairSync非公平锁的加锁和尝试获取锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
// 通过判断当前线程是否获取锁的线程来决定获取操作是否成功,如果同步状态值成功修改,那就代表当前线程获取到了锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
// 调用的是父类Sync的尝试获取锁的方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
释放锁
unlock 释放锁的方法,底层调用的是 Sync 同步器的 release 方法,release 是 AQS 的方法,分成两步:
- 尝试释放锁,如果释放失败,直接返回 false;
- 释放成功,从同步队列的头节点的下一个节点开始唤醒,让其去竞争锁。
第一步就是我们上文中 Sync 的 tryRelease 方法(4.1),第二步 AQS 已经实现了。
释放锁通过LockSupport.unpark(s.thread);
unLock 的源码如下:
// 释放锁
public void unlock() {
sync.release(1);
}
ReentrantLock-源码解析的更多相关文章
- 第六章 ReentrantLock源码解析2--释放锁unlock()
最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...
- 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...
- ReentrantLock源码解析
ReentrantLock 1 数据结构 从上图可以看出,ReentrantLock的功能都是通过sync这个对象提供的. public class ReentrantLock implements ...
- 深入浅出ReentrantLock源码解析
ReentrantLock不但是可重入锁,而且还是公平或非公平锁,在工作中会经常使用到,将自己对这两种锁的理解记录下来,希望对大家有帮助. 前提条件 在理解ReentrantLock时需要具备一些基本 ...
- Java并发之ReentrantLock源码解析(二)
在了解如何加锁时候,我们再来了解如何解锁.可重入互斥锁ReentrantLock的解锁方法unlock()并不区分是公平锁还是非公平锁,Sync类并没有实现release(int arg)方法,这里会 ...
- Java并发之ReentrantLock源码解析(四)
Condition 在上一章中,我们大概了解了Condition的使用,下面我们来看看Condition再juc的实现.juc下Condition本质上是一个接口,它只定义了这个接口的使用方式,具体的 ...
- 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁
问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...
- ReentrantLock源码解析——虽众但写
在看这篇文章时,笔者默认你已经看过AQS或者已经初步的了解AQS的内部过程. 先简单介绍一下ReentantLock,跟synchronized相同,是可重入的重量级锁.但是其用法则相当不同,首先 ...
- Java并发之ReentrantLock源码解析(三)
ReentrantLock和BlockingQueue 首先,看到这个标题,不要怀疑自己进错文章,也不要怀疑笔者写错,哈哈.本章笔者会从BlockingQueue(阻塞队列)的角度,看看juc包下的阻 ...
- 第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()
最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...
随机推荐
- 【题解】Generator(UVA1358)
感觉我字符串和期望都不好-- 题目链接 题意 有 \(n\) 种字符,给定一个模式串 \(S\) ,一开始字符串为空,现在每次随机生成一个 1~n 的字符添加到字符串末尾,直到出现 \(S\) 停止, ...
- TMOOC-1692-分西瓜
题目 描述 今天是阴历七月初五,首师大附中信息社团队员GDC的生日.GDC正在和SCX.WXY在首师大附中集训.他想给这两位兄弟买点什么庆祝生日,经过调查,GDC发现SCX和WXY都很喜欢吃西瓜,而且 ...
- webstorm实现手机预览页面
效果:在webstorm中开发页面,复制该页面在电脑中的浏览网址,发给手机,在手机上点击链接,可以直接访问本地开发的页面.并且,电脑上修改后保存,手机上刷新即可看到效果. 步骤: 1.webstorm ...
- 微信公众测试号中的url和token
我设置的前提条件: 已购买阿里云服务器,开通了80端口,且网站已备案. 1.在网站文件中新建index.php文件.该文件内容如下: 把 define("TOKEN", " ...
- cocosCreator微信小游戏排行榜思路
cocosCreator制作微信小游戏排行榜实现方案: 游戏认知:项目分为主域和子域,主域就是游戏主程部分,子域为单独处理微信排行榜公共域数据的. 游戏主域里创建一个节点,添加WXSubContext ...
- adb devices查看不到Android模拟器的设备
1.先开启模拟器,后执行adb devices命令: List of devices attached 2.找到SDK的安装目录下platform-tools文件夹下adb.exe文件,将其复制到桌面 ...
- Docker修改默认的网段
一,问题 docker安装后默认的网段是172.17网段的,和真实环境网段冲突导致本机电脑无法连接docker机器. 二,解决办法 修改docker默认网段 1,先把docker停止 systemct ...
- 热部署Devtools
在子工程添加devtools的依赖 <dependency> <groupId>org.springframework.boot</groupId> <art ...
- kali 开启Mysql设置远程连接管理
环境工具 kali2020.01 192.168.177.137 windows10物理机heidiSQL工具下载地址 https://www.heidisql.com/download.php 开启 ...
- Attention & Transformer
Attention & Transformer seq2seq; attention; self-attention; transformer; 1 注意力机制在NLP上的发展 Seq2Seq ...