ReentrantLock可重入、可打断、Condition原理剖析
本文紧接上文的AQS源码,如果对于ReentrantLock没有基础可以先阅读我的上一篇文章学习ReentrantLock的源码
ReentrantLock锁重入原理
重入加锁其实就是将AQS的state进行加一操作
然后释放锁资源将AQS的state进行减一操作
当state为0时才会彻底的释放锁资源
ReentrantLock可打断原理
在ReentrantLock中可打断就是在等待锁的过程中可以被interrupt打断(需要调用lockInterruptibly),lock方法设置了打断标记,但是只有在线程获得锁的时候才能知道自己有没有在阻塞的过程中有没有被打断。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted; // 返回打断标记
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())// 我们这边会检查打断,如果打断的话返Thread.interrupted()
interrupted = true; // 这里将打断标记置为true后,继续进入循环。直到获得到锁返回标记
}
} finally {
if (failed)
cancelAcquire(node);
}
}
首先我们需要调用加锁的lockInterruptibly()方法
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
可打断主要原因在如下代码解释。用异常代替了返回标记,让线程可以直接再park的过程中直接结束
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException(); // 再被打断的时候不会将其标记置为true,而是直接抛出一个异常,打断当前的等待。
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ReentrantLock条件变量原理
Condition是一个接口,实际上是ReentrantLock的ConditionObject类作为其实现类。
首先我们创建一个condition就会调用其构造方法。其实就是产生一个新的conditionObject
final ConditionObject newCondition() {
return new ConditionObject();
}
await()源码
接下来,简单剖析一个源码
- 首先我们得知道,ConditionObject中维护着一个等待的双向链表,其实和阻塞链表是很相似的,不同在于不需要前驱进行唤醒。然后在ConditionObject中维护头和尾的引用就是firstWaiter和lastWaiter成员变量。
public final void await() throws InterruptedException {
if (Thread.interrupted()) // 如果被打断,抛异常
throw new InterruptedException();
Node node = addConditionWaiter(); // 1.向AQS中添加一个等待链表的node
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) { // 是否在阻塞链表中
LockSupport.park(this); // 不是的话直接进行阻塞起来
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)// 被打断了就得把它放阻塞链表
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE) // 多线程的遗留状态处理
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
- 添加等待node
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters(); // 这个和阻塞队列相似不过是全部遍历,清除不在等待队列上的node
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null) // 添加到waitting尾部
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
signal源码
signal唤醒源码,简单介绍就是直接将等待的firstWaiter指向的等待链表的第一个进行解除阻塞,然后将其放入阻塞链表中。不过多赘述。
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
ReentrantLock可重入、可打断、Condition原理剖析的更多相关文章
- ReentrantLock——可重入锁的实现原理
一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...
- ReenTrantLock可重入锁(和synchronized的区别)总结
ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...
- ReenTrantLock可重入锁和synchronized的区别
ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...
- JUC 一 ReentrantLock 可重入锁
java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...
- ReentrantLock可重入锁的理解和源码简单分析
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author ...
- 【java并发编程】ReentrantLock 可重入读写锁
目录 一.ReentrantLock可重入锁 二.ReentrantReadWriteLock读写锁 三.读锁之间不互斥 欢迎关注我的博客,更多精品知识合集 一.ReentrantLock可重入锁 可 ...
- ReentrantLock可重入锁、公平锁非公平锁区别与实现原理
ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...
- Java并发包源码学习系列:ReentrantLock可重入独占锁详解
目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...
- java ReentrantLock可重入锁功能
1.可重入锁是可以中断的,如果发生了死锁,可以中断程序 //如下程序出现死锁,不去kill jvm无法解决死锁 public class Uninterruptible { public static ...
随机推荐
- Mybatis入门程序(二)
1.实现需求 添加用户 更新用户 删除用户 2.添加用户 (1)映射文件User.xml(Mapper)中,配置添加用户的Statement <!-- 添加用户: parameterType:指 ...
- 学习Solr(三)
本文以solr5为例说明在linux系统上单机安装过程. 一. solr的安装 1. solr能够安装在不同的操作系统上,安装solr前需要安装何时的JRE.当前版本5.5最低需要JRE1. ...
- 学习GlusterFS(五)
一,分布式文件系统理论基础 1.1 分布式文件系统出现 计算机通过文件系统管理,存储数据,而现在数据信息爆炸的时代中人们可以获取的数据成指数倍的增长,单纯通过增加硬盘个数来扩展计算机文件系统的存储容量 ...
- Streamlit:快速数据可视化界面工具
目录 Streamlit简介 Streamlit使用指南 常用命令 显示文本 显示数据 显示图表 显示媒体 交互组件 侧边栏 缓存机制 Streamlit使用Hack Streamlit的替代品 相关 ...
- 伪元素的margin值挤压主体元素解决
伪元素的margin值挤压主体元素解决 主体是两个p标签,需要再其左侧添加一个竖线,很常见的需求 目标 前提条件 1. 右侧的文字个数不固定 问题 1. 需要让before元素为`float:left ...
- AS修改text内容+显示不同页面
新创建一个project,命名为myclass. 一:修改 在res中找到layout打开xml文件,右上角有一个code,点击进入可以写代码的文件,并在里面进行修改.(老版本写代码的界面在下面与de ...
- 人机交互BS
B/S结构用户界面设计 [实验编号] 10003809548j Web界面设计 [实验学时] 8学时 [实验环境] l 所需硬件环境为微机: l 所需软件环境为dreamweaver ...
- 大数据学习之路之ambari配置(四)
试了很多遍,内存还是不够,电脑不太行的,不建议用ambari!!! 放弃了
- git总是需要输入用户名密码问题解决
解决办法: git bash进入你的项目目录,输入: git config --global credential.helper store 然后你会在你本地生成一个文本,上边记录你的账号和密码.当然 ...
- Input框搜索关键字高亮显示
ruleTitle(text, val) { if (!val) return text; const result = text.replace( new RegExp(val, "g&q ...