Java 显示锁 之 重入锁 ReentrantLock(七)
ReentrantLock 重入锁简介
重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁。另外,该锁还支持获取锁时的公平与非公平性的选择。
重入锁 ReentrantLock,只支持独占方式的获取操作,因此它只实现了 tryAcquire、tryRelease 和 isHeldExclusively 方法。
ReentrantLock 如何实现锁重入
锁重入是指任意线程在获取到锁之后,能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决两个问题:
1、线程再次获取锁
需要识别获取锁的线程是否为当期占有锁的线程,如果是,则便获取锁成功
2、锁最终得到释放
同一个线程重复 n 次获得了锁,在第 n 次释放该锁后,其它线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时,表示锁已经成功释放
ReentrantLock 是通过自定义同步器来实现所得获取和释放,默认使用非公平性,下面就以非公平性获取锁为例,学习重入锁是如何实现的:
final boolean nonfairTryAcquire(int acquires) {
//当前线程
final Thread current = Thread.currentThread();
//当前同步状态
int c = getState();
//当前同步状态等于0,说明当前线程可以获取同步状态
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;
}
通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程,则将同步状态值进行累加并返回true,表示获取同步状态成功。
成功获取锁的线程再次获取锁,只是增加了同步状态值,这也就要求在释放同步状态时递减同步状态的值。如下,释放锁的代码:
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
如果该锁被获取了n次, 那么前( n- 1) 次 tryRelease( int releases) 方法必须返回false,只有同步状态完全释放了,才能返回tru。 该方法将同步状态 是否为 0 作为作为最终释放的条件,当同步状态为0时,将该锁的拥有者线程设置为null,并返回true,表示成功释放。
ReentrantLock 如何实现锁的公平性与非公平性
公平性与否是针对获取锁而言的,如果一个锁时公平的,那么锁的获取顺序就应该服务请求时间的顺序,也就是FIFO。
由上文介绍的非公平获取锁方法 nonfairTryAcquire( int acquires) 可知,只要CAS设置同步状态成功,则表示线程获取了锁,而公平锁则不同,如代码所示:
static final class FairSync extends Sync {
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return 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;
}
}
该方法与 nonfairTryAcquire( int acquires) 的区别在于多了hasQueuedPredecessors() 方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早的请求了锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。
Java 显示锁 之 重入锁 ReentrantLock(七)的更多相关文章
- 浅谈Java中的公平锁和非公平锁,可重入锁,自旋锁
公平锁和非公平锁 这里主要体现在ReentrantLock这个类里面了 公平锁.非公平锁的创建方式: //创建一个非公平锁,默认是非公平锁 Lock lock = new ReentrantLock( ...
- java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解
一.公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解 公平锁:多个线程按照申请的顺序来获取锁. 非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关.[ReentrantLock 默认非公平.s ...
- 可重入锁 & 不可重入锁
可重入锁指同一个线程可以再次获得之前已经获得的锁,避免产生死锁. Java中的可重入锁:synchronized 和 java.util.concurrent.locks.ReentrantLock. ...
- 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁
1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...
- redis分布式锁-可重入锁
redis分布式锁-可重入锁 上篇redis实现的分布式锁,有一个问题,它不可重入. 所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞. 同一个 ...
- Java多线程系列——深入重入锁ReentrantLock
简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...
- java线程的同步控制--重入锁ReentrantLock
我们常用的synchronized关键字是一种最简单的线程同步控制方法,它决定了一个线程是否可以访问临界区资源.同时Object.wait() 和Object.notify()方法起到了线程等待和通知 ...
- Java并发包4--可重入锁ReentrantLock的实现原理
前言 ReentrantLock是JUC提供的可重入锁的实现,用法上几乎等同于Synchronized,但是ReentrantLock在功能的丰富性上要比Synchronized要强大. 一.Reen ...
- Java并发编程-可重入锁
可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响.在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁. publ ...
随机推荐
- HTTP协议探究(三):HTTPS
一 复习与目标 1 复习 代理:转发通信数据(一般协议不变,作为中间人,可对报文进行过滤修改) 网关:转发通信数据(协议改变,作为资源拥有者) 隧道:转发通信数据(协议不变,作为管道,不对报文进行过滤 ...
- css加载没效果,查看网络显示类型为 text/plain 的解决方法
当请求的css 文件的MIME 类型 为 text/plain 时,文件会当做 .txt 文件来处理,浏览器就会拒绝渲染 产生这样的问题和服务器的配置有关系 在服务器上加上下面两句就好了 搞定
- VmWare 网络模式
VMware虚拟机三种联网方法及原理 一.Brigde--桥接:默认使用VMnet0 1.原理: Bridge 桥"就是一个主机,这个机器拥有两块网卡,分别处于两个局域网中,同时在" ...
- Python打
.智能识别图片物体.这步是智能垃圾分类的魔法核心.原理是人工智能会根据打上标签的海量图片来识别新的图片所归属的分类标签.好奇的读者可能会问,我没学过深度学习啊?我也不会训练模型,怎么办? python ...
- Js-带进度条的轮播图
带进度条的轮播图--原生JS实现 实现了图片自动轮播,左右按钮实现图片左右转换,下方原点或者缩小图点击选择其中的某一张图片,然后有红条实现图片的进度. <div class="cont ...
- elmentUI为table中的单元格添加事件
<el-main> <el-tabs v-model="curTab" type="card"> <!-- tab签 --> ...
- 安卓开发之利用XmlSerializer生成XML文件
package com.lidaochen.phonecall; import android.net.Uri; import android.os.Environment; import andro ...
- 四、DML语言
目录 简介 主要操作 插入语句 语法 修改语句 修改单表 删除语句 DELETE TRUNCATE 两种删除总结 简介 DML语言就是数据操作语言 主要操作 插入:insert 修改:update 删 ...
- 通过快捷方式lnk获得文件真实路径
通过快捷方式.lnk获得文件真实路径前提最近开发资源管理,需要预先上传大量资源,负责整理资源的同学因为空间不足,直接用快捷键方式整理视频资源OTZ,所以只能想办法通过.lnk文件获得文件的真实地址. ...
- Matlab---绘图及其位置摆放
Matlab---绘图及其位置摆放 [@WP@20180509] 一.绘图函数 (1)绘制二维图形 (1.1) plot( ) 函数的应用格式. 1,plot(x). 当x 为一向量时,以x 元素的值 ...