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 ...
随机推荐
- 学习Squid(三)
Squid 缓存服务 1.缓存服务器结束 缓存服务器(cache server),即用来存储(介质为内存及硬盘)用户访问的网页.图片.文件等等信息的专用服务器,这种服务器不仅可以使用户可以最快的得到他 ...
- 《剑指offer》面试题1:赋值运算函数
面试题1:赋值运算函数 题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数 class CMyString { public: CMyString(char* pData = NU ...
- C语言泛型编程——泛型冒泡排序
在实际编程中,常常会需要一些方法(函数),比如排序,它们具体实现基本一致,仅仅只有参数类型不同, 那么可不可以有一种通用的函数,不管是什么类型的参数都可以通用呢? 泛型编程:泛型即是指具有在多种数据类 ...
- 玩转 React(四)- 创造一个新的 HTML 标签
在第二篇文章 <新型前端开发方式> 中有说到 React 有很爽的一点就是给我们一种创造 HTML 标签的能力,那么今天这篇文章就详细讲解下 React 是如何提供这种能力的,作为前端开发 ...
- electron制作聊天界面(仿制qq)
效果图: 样式使用scss和flex布局 这也是制作IM系统的最后一个界面了!在制作之前参考了qq和千牛 需要注意的点 qq将滚动条美化了 而且在无操作的情况下是不会显示的 滚动条美化 ::-webk ...
- table表格做出圆角效果
采用border-radius 这个属性的时候在chrome里面没有圆角,倒是在IE里面有圆角. 不知道是不是没有写webkie 前缀,但是加上一段神奇的代码overflow:hidden的是时候在c ...
- C语言-操作符与表达式
C语言入门之操作符与表达式 前言 本篇文章主要包括各种操作符的介绍与表达式求值,欢迎各位小伙伴与我一起学习. 一.操作符 分类 算术操作符 移位操作符 位操作符 赋值操作符 单目运算符 关系操作符 逻 ...
- Docker入门(windows版),利用Docker创建一个Hello World的web项目
Docker 当大家点开这篇博客的时候,相信大家对docker多多少少也有些认识了,最近学习docker这门技术,略微有些心得,写篇文章记录一下学习过程并帮大家跳过一些坑. docker的核心有两个, ...
- SpringMVC-自定义转换器
1.定义转换器类实现Converter接口 import org.springframework.core.convert.converter.Converter; import java.text. ...
- JAVA学习2——HelloWorld
Java语言的诞生.版本以及工具:Java的安装开发环境以及环境变量的配置:第一个Java程序--HelloWorld