ReentrantLock可重入锁、公平锁非公平锁区别与实现原理
ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁
ReentrantLock公平锁和不公平锁实现原理
公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取锁就会失败,并且会加入阻塞队列
非公平锁获取锁时不会判断阻塞队列是否有线程再等待,所以对于已经在等待的线程来说是不公平的,但如果是因为其它原因没有竞争到锁,它也会加入阻塞队列
进入阻塞队列的线程,竞争锁时都是公平的,应为队列为先进先出(FIFO)
默认实现的是非公平锁
public ReentrantLock() {
//非公平锁
sync = new NonfairSync();
}
还提供了另外一种方式,可传入一个boolean值,true时为公平锁,false时为非公平锁
//公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
非公平锁
非公平锁获取锁nonfairTryAcquire
方法,对锁状态进行了判断,并没有把锁加入同步队列中
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
//比较当前状态 如果持有者是当前线程
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//如果不是 尝试获取锁
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
//获取锁
return nonfairTryAcquire(acquires);
}
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//判断当前对象是否被持有
if (c == 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;
}
公平锁
代码和nonfairTryAcquire
唯一的不同在于增加了hasQueuedPredecessors
方法的判断
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
int c = getState();
//判断当前对象是否被持有
if (c == 0) {
//如果等待队列为空 并且使用CAS获取锁成功 否则返回false然后从队列中获取节点
if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {
//把当前线程持有
setExclusiveOwnerThread(current);
return true;
}
}
//若被持有 判断锁是否是当前线程 可重入锁的关键代码
else if (current == getExclusiveOwnerThread()) {
//计数加1 返回
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//不是当前线程持有 执行
return false;
}
}
acquire()获取锁
public final void acquire(int arg) {
//如果当前线程尝试获取锁失败并且 加入把当前线程加入了等待队列
if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//先中断当前线程
selfInterrupt();
}
关键代码
就是tryAcquire
方法中hasQueuedPredecessors
判断队列是否有其他节点
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
可重入性实现原理
在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功
由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功
1、获取锁方法
protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
int c = getState();
//判断当前对象是否被持有
if (c == 0) {
//...略
}
//若被持有 判断锁是否是当前线程 可重入锁的关键代码
else if (current == getExclusiveOwnerThread()) {
//计数加1 返回
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//不是当前线程持有 执行
return false;
}
每次如果获取到的都是当前线程这里都会计数加1
释放锁
protected final boolean tryRelease(int releases) {
//每次释放都减1
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//等于0才释放锁成功
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
如果锁被获取n次,也要释放了n次,只有完全释放才会返回false
ReentrantLock可重入锁、公平锁非公平锁区别与实现原理的更多相关文章
- Java中的常见锁(公平和非公平锁、可重入锁和不可重入锁、自旋锁、独占锁和共享锁)
公平和非公平锁 公平锁:是指多个线程按照申请的顺序来获取值.在并发环境中,每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个就占有锁,否者就会加入到等待队列中,以 ...
- ReentrantLock——可重入锁的实现原理
一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...
- JUC 一 ReentrantLock 可重入锁
java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...
- J.U.C之ReentrantLock 可重入锁
* A reentrant mutual exclusion {@link Lock} with the same basic * behavior and semantics as the impl ...
- Java并发包源码学习系列:ReentrantLock可重入独占锁详解
目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...
- ReentrantLock可重入锁——源码详解
开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...
- ReenTrantLock可重入锁(和synchronized的区别)总结
ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...
- ReenTrantLock可重入锁和synchronized的区别
ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...
- ReentrantLock可重入锁的理解和源码简单分析
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author ...
- Java多线程系列--“JUC锁”05之 非公平锁
概要 前面两章分析了"公平锁的获取和释放机制",这一章开始对“非公平锁”的获取锁/释放锁的过程进行分析.内容包括:参考代码获取非公平锁(基于JDK1.7.0_40)释放非公平锁(基 ...
随机推荐
- vue 引用高德地图
vue 引用地图之傻瓜式教程(复制粘贴即可用) npm 下载 npm install vue-amap --save main.js 代码 import AMap from 'vue-amap'; V ...
- “ShardingCore”是如何针对分表下的分页进行优化的
分表情况下的分页如何优化 首先还是要给自己的开原框架打个广告 sharding-core 针对efcore 2+版本的分表组件,首先我们来快速回顾下目前市面上分表下针对分页常见的集中解决方案 分表解决 ...
- 20210713考试-2021noip14
T1 队长快跑 #include<bits/stdc++.h> using namespace std; const int N=1e6+5,INF=0x7fffffff; int n,a ...
- Activiti 学习(二)—— Activiti 流程定义和部署
概述 在这一节,我们将创建一个 Activit 工作流,并启动这个流程,主要包含以下几个步骤: 定义流程,按照 BPMN 的规范,使用流程定义工具,用流程符号把整个流程描述出来 部署流程,把画好的流程 ...
- Spring全自动AOP和项目加入jar包
一.jar可以引进项目中,复制到路下后,要add as library,加载到工作空间中才能引入: 也jar包放在硬盘的项目目录外面,可以多个项目引入共用: 二.xml配置 1.aop全自动配置 2. ...
- python模块--__future__(向上兼容模块)
py2.7 unicode_literals 将字符串默认视为unicode, 即u'xxx'和'xxx'将是一样的, 而再想表示字节需用b'xxx'表示 division / 将表示正常除法操作 ...
- [第一篇]——Docker 教程之Spring Cloud直播商城 b2b2c电子商务技术总结
Docker 教程 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然 ...
- study day2
study day2 windows 常用快捷键 CTRL C:复制 CTRL V:粘贴 CTRL A:全选 CTRL X:剪切 CTRL S:保存 CTRL Z:撤销 alt f4:关闭窗口 shi ...
- java版gRPC实战之六:客户端动态获取服务端地址
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- python matplotlib.pyplot 散点图详解(2)
python matplotlib.pyplot 散点图详解(2) 上期资料 一.散点图叠加 可以用多个scatter函数叠加散点图 代码如下: import matplotlib.pyplot as ...