java中AQS源码分析
AQS内部采用CLH队列。CLH队列是由节点组成。内部的Node节点包含的状态有
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
其中取消状态表示任务的取消,SIGNAL状态表示后续节点需要唤醒,CONDITION表示等待状态,PROPAGRATE表示的是传播状态通常用于共享锁的释放。初始节点的状态为0。
AQS中比较重要的操作包括:
public final void acquire(int arg);
public final void acquireInterruptibly(int arg);
public final void acquireShared(int arg);
public final void acquireSharedInterruptibly(int arg);
protected boolean tryAcquire(int arg);
protected int tryAcquireShared(int arg);
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException;
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException;
其中:public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
其中tryAcquire方法为抽象方法。不同的子类有不同的实现方式。AQS中该方法的实现知识抛出了一个异常。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;//标记是否成功拿到资源
try {
boolean interrupted = false;//标记等待过程中是否被中断过
//自旋的过程
for (;;) {
final Node p = node.predecessor();//拿到前驱
//如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。
if (p == head && tryAcquire(arg)) {
setHead(node);//拿到资源后,将head指向该结点。所以head所指的标杆结点,就是当前获取到资源的那个结点或null。
p.next = null; // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了!
failed = false;
return interrupted;//返回等待过程中是否被中断过
}
//如果自己可以休息了,就进入waiting状态,直到被unpark()
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;//如果等待过程中被中断过,哪怕只有那么一次,就将interrupted标记为true
}
} finally {
if (failed)
cancelAcquire(node);
}
}
可以从该方法中看出。这里会继续尝试去获取一下资源
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;//拿到前驱的状态
if (ws == Node.SIGNAL)
//如果已经告诉前驱拿完号后通知自己一下,那就可以安心休息了
return true;
if (ws > 0) {
/*
* 如果前驱放弃了,那就一直往前找,直到找到最近一个正常等待的状态,并排在它的后边。
* 注意:那些放弃的结点,由于被自己“加塞”到它们前边,它们相当于形成一个无引用链,稍后就会被保安大叔赶走了(GC回收)!
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//如果前驱正常,那就把前驱的状态设置成SIGNAL,告诉它拿完号后通知自己一下。有可能失败,人家说不定刚刚释放完呢!
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
在该方法中会检测当前节点中前面的节点是否有CANCELLED状态的如果有。待会儿后续的操作这些节点会被GC回收。
如果一切正常当前节点的前一个节点会被设置为SIGNAL状态。
1 private final boolean parkAndCheckInterrupt() {
2 LockSupport.park(this);//调用park()使线程进入waiting状态
3 return Thread.interrupted();//如果被唤醒,查看自己是不是被中断的。
4 }
线程进入waiting状态。线程被唤醒的方式有被unpark和被中断。
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;//找到头结点
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);//唤醒等待队列里的下一个线程
return true;
}
return false;
}
这里tryRelease也是一个抽象方法不同的子类有不同的实现。
private void unparkSuccessor(Node node) 内部首先会设置当前节点的状态为初始状态。同时找到一个有效的后继节点的状态小于0的进行节点的释放。 LockSupport.unpark(s.thread);//唤醒对应的线程。
java中AQS源码分析的更多相关文章
- Java中ArrayList源码分析
一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...
- Java中HashMap源码分析
一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...
- java中LinkedList源码分析
ArrayList是动态数组,其实本质就是对数组的操作.那么LinkedList实现原理和ArrayList是完全不一样的.现在就来分析一下ArrayList和LinkeList的优劣吧LinkedL ...
- ReentrantLock 与 AQS 源码分析
ReentrantLock 与 AQS 源码分析 1. 基本结构 重入锁 ReetrantLock,JDK 1.5新增的类,作用与synchronized关键字相当,但比synchronized ...
- 并发-AQS源码分析
AQS源码分析 参考: http://www.cnblogs.com/waterystone/p/4920797.html https://blog.csdn.net/fjse51/article/d ...
- 【原】Spark中Client源码分析(二)
继续前一篇的内容.前一篇内容为: Spark中Client源码分析(一)http://www.cnblogs.com/yourarebest/p/5313006.html DriverClient中的 ...
- 【JAVA】ThreadLocal源码分析
ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...
- 【Java】HashMap源码分析——常用方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...
- 【Java】HashMap源码分析——基本概念
在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...
随机推荐
- 使用python解线性矩阵方程(numpy中的matrix类)
这学期有一门运筹学,讲的两大块儿:线性优化和非线性优化问题.在非线性优化问题这里涉及到拉格朗日乘子法,经常要算一些非常变态的线性方程,于是我就想用python求解线性方程.查阅资料的过程中找到了一个极 ...
- 为避免种族歧视,谷歌Chrome将不再使用“黑名单”等词
GitHub 15.2k Star 的Java工程师成神之路,不来了解一下吗! GitHub 15.2k Star 的Java工程师成神之路,不来了解一下吗! 近日,美国黑人乔治‧佛洛伊德(Georg ...
- ComplexHeatmap|根据excel表绘制突变景观图(oncoplot)
本文首发于“生信补给站”:https://mp.weixin.qq.com/s/8kz2oKvUQrCR2_HWYXQT4g 如果有maf格式的文件,可以直接oncoplot包绘制瀑布图,有多种展示和 ...
- WINCC 应用与提高(78讲15.98G)视频教程网盘下载
收集与网络,供参考. https://blog.csdn.net/txwtech/article/details/94225748
- Android安全初学笔记
安全概述 安全主要解决4类问题 保密:不希望第三方窥探 鉴别:与你通信的人可以被确认 完整性:不能被随意篡改,或者能鉴别是否被篡改 不可否认性:能确认产生信息的人,并且产生该信息的人在何时都无法否认产 ...
- WeChair项目Alpha冲刺(9/10)
团队项目进行情况 1.昨日进展 Alpha冲刺第九天 昨日进展: 前端:安排页面美化,设计实名认证 后端:更新dao层代码 数据库:修改数据表属性,与后端部署数据库交互 2.今日安排 前端:继续 ...
- linux kernel update
linux内核升级 最近HW行动,报出来的linux系统内核漏洞,环境中全部是2.6.32-431.el6.x86_64的主机,需要全部升级到754版本,这也是第一次进行内核升级操作. 先找了一台和生 ...
- sqlserver导致服务器异常卡死
1.业务反应,服务器三天两头就要重启一次,要不然直接hang掉,登上服务器,异常的慢,大概进去需要十分钟的时间,查看一下电脑配置,8核8G的物理机. 2.查看一下任务管理器中的资源使用情况,发现cpu ...
- shell编程之系统环境变量2
本课程是<Tony老师聊shell——变量>课程的延续,主要介绍Linux shell编程基础中的运算符.包括declare命令.数值运算方法和变量测试.首先在declare命令中介绍了数 ...
- SSM中保存数据出现415错误
服务器415错误 ssm框架的controller jsp页面 问题:页面出现415错误 原因:请求和响应类型不一致 分析: 先排除以下基本的环境配置 1.URL路径对应好,视图解析器配置好,cont ...