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 ...
随机推荐
- Jmeter(三十三) - 从入门到精通 - Jmeter Http协议录制脚本工具-Badboy6(详解教程)
1.简介 今天分享的就是在上一篇文章的基础上来进行讲解和分享:Badboy使用数据源Excel进行脚本参数化.然后在使用读取的参数进行对比断言. 2.具体场景 Badboy录制一个搜索的脚本,并对搜索 ...
- CSP-S2020初赛游记
前一星期 感觉没怎么复习初赛啊,经常旷初赛练习赛--整天刷复赛题被老师怒斥了. zhoukangyang 天天做初赛(但是一天还是稳定做 \(2\) 道黑题),是不是要 AK 了啊(慌... 前一天 ...
- 数组问题:a[i][j] 和 a[j][i] 有什么区别?
本文以一个简单的程序开头--数组赋值: int LEN = 10000; int[][] arr = new int[LEN][LEN]; for (int i = 0; i < LEN; i+ ...
- [日常摸鱼]bzoj1038 [ZJOI2008]瞭望塔-模拟退火/几何
题意:给一条平面内$n$个点的折线,要求在折线上搞一个高度$h$的瞭望塔,能够看见折线上所有的点,求$h$的最小值($n \leq 300$) updata2018.1.21 正解半平面交在另一篇里面 ...
- MAC 安装Python3.7
查看下python版本 macosdeMacBook:Versions macos$ cd /System/Library/Frameworks/Python.framework/Versions/ ...
- Numpy的学习1-创建数据基础
1 import numpy as np 2 3 array = np.array([[1,2,3],[4,5,6]]) 4 5 print(array) 6 print('number of dim ...
- java基础:方法的定义和调用详细介绍,方法同时获取数组最大值和最小值,比较两个数组,数组交换最大最小值,附练习案列
1. 方法概述 1.1 方法的概念 方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集 注意: 方法必须先创建才可以使用,该过程成为方法定义 方法创建后并不是直接可 ...
- Python 写了一个批量生成文件夹和批量重命名的工具
Python 写了一个批量生成文件夹和批量重命名的工具 目录 Python 写了一个批量生成文件夹和批量重命名的工具 演示 功能 1. 可以读取excel内容,使用excel单元格内容进行新建文件夹, ...
- CCNP之MERG实验报告
MGRE实验报告 一.实验要求: 1.R5为ISP,只能配置IP地址 2.R1--R3间建立MGRE环境,且使用EIGRP来学习各自环回 3.R4可以正常访问R5的环回 4.R1与R5进行chap认证 ...
- 【进程/作业管理】篇章一:Linux进程及其管理(系统监控类工具)----glances、dstat
glances dstat glances命令详解 相对于htop工具的使用,这里介绍一下glances工具的使用,我个人是比较喜欢这款工具的,主要就是由于glances这款工具可以将系统状态 ...