本文紧接上文的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);
}
  1. 添加等待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原理剖析的更多相关文章

  1. ReentrantLock——可重入锁的实现原理

    一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...

  2. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  3. ReenTrantLock可重入锁和synchronized的区别

    ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...

  4. JUC 一 ReentrantLock 可重入锁

    java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...

  5. ReentrantLock可重入锁的理解和源码简单分析

    import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author ...

  6. ReentrantLock可重入锁、公平锁非公平锁区别与实现原理

    ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...

  7. Java并发包源码学习系列:ReentrantLock可重入独占锁详解

    目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...

  8. java ReentrantLock可重入锁功能

    1.可重入锁是可以中断的,如果发生了死锁,可以中断程序 //如下程序出现死锁,不去kill jvm无法解决死锁 public class Uninterruptible { public static ...

  9. J.U.C之ReentrantLock 可重入锁

    * A reentrant mutual exclusion {@link Lock} with the same basic * behavior and semantics as the impl ...

  10. ReentrantLock可重入锁——源码详解

    开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...

随机推荐

  1. MySQL三大数据类型

  2. Ubuntu下搭建java开发环境

    JDK安装: 1. 在http://www.oracle.com/technetwork/java/javase/downloads/index.html上下载相应版本的JDK环境,这里我使用的是jd ...

  3. MDX : Non Empty v/s NonEmpty

    MDX : Non Empty v/s NonEmpty User Rating: / 50 PoorBest Written by Jason Thomas    Friday, 07 May 20 ...

  4. lightoj 1407 2-sat

    这题的英语either...or....很蛋疼: m中,1:x与y至少一个出席:2:x出席,y随便,x不出席,y也不出席----这有个坑,可以推出y出席x也一定出席(这个关系必须要连上):3x与y至少 ...

  5. Windows下搭建objective C开发环境

    摘自:http://blog.csdn.net/zhanghefu/article/details/18320827 最近打算针对iPhone.iPod touch和iPad开发一些应用,所以,需要开 ...

  6. Windows下配置Git多账号github码云

    Windows下配置Git多账号github码云 1.配置了全局用户名和邮箱 $ git config --global user.email "你的邮箱" $ git confi ...

  7. Beta 冲刺(1/7)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(1/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 团队完成测试答辩 整理博客 复习接口 接下来的 ...

  8. 【转】C++命名空间 namespace的作用和使用解析

    一. 为什么需要命名空间(问题提出) 命名空间是ANSIC++引入的可以由用户命名的作用域,用来处理程序中 常见的同名冲突. 在 C语言中定义了3个层次的作用域,即文件(编译单元).函数和复合语句.C ...

  9. Bootstrap框架(一)

    day57 参考:https://www.cnblogs.com/liwenzhou/p/8214637.html 下载:http://www.bootcss.com/   选择用于生产环境的 Boo ...

  10. 17_常用API_第17天(包装类、System、Math、Arrays、大数据运算)_讲义

    今日内容介绍 1.基本类型包装类 2.System类 3.Math类 4.Arrays类 5.大数据运算 01基本数据类型对象包装类概述 *A:基本数据类型对象包装类概述 *a.基本类型包装类的产生 ...