AQS,全称AbstractQueuedSynchronizer,是Concurrent包锁的核心,没有AQS就没有Java的Concurrent包。它到底是个什么,我们来看看源码的第一段注解是怎么说明



看完第一段,总结下

  • AQS是一个同步的基础框架,基于一个先进先出的队列。
  • 锁机制基于一个状态值,它是原子值。
  • AQS的子类负责定义与操作这个状态值,但必须通过AQS提供的原子操作
  • AQS剩余的方法就是围绕队列,与线程阻塞唤醒等功能

基于以上概念,我们看看源码到底是这么实现这些功能的

AQS的成员变量

state

private volatile int state;
该变量标记为volatile,说明该变量是对所有线程可见的。作用在于每个线程改变该值,都会马上让其他线程可见,在CAS(可见锁概念与锁优化)的时候是必不可少的。在AQS类中,不会直接操作这个值,而是交由它的子类去操作和定义他的作用。

Node、head、tail

AQS中有一个静态内部类Node,其实现是一个双向链表。headtail则是这个链表的头尾指针。作用是存储获取锁失败的阻塞线程。同样的,这个链表是会被多个线程操作的,所以它里面的变量多是被标记为volatile,并且操作也要通过CAS等原子方法去执行。
Node还有一个模式的属性:独占模式共享模式。独占模式下,锁是线程独占的,而共享模式下,锁是可以被多个线程占用的。

VarHandler

对于大多数需要操作的原子属性,都对应会有一个大写的值,它的类是VarHandler。例如state、head、tail都有对应的VarHandler,STATE、HEAD、TAIL。VarHandler是1.9的新特性,提供了类似于原子操作以及Unsafe操作的功能,里面的原子操作大多是native方法,比较难查看源码。

ConditionObject

条件队列,是AQS中一个非常关键内部类。这个名字起非常奇异,让人搞不懂,看它类注释也看不懂说了什么。看看AQS头部注解

这个类是为了让子类支持独占模式的。深入看其中的源码实现,其实就是Node在功能性上的封装,最终让子类实现让当前线程怎么独占一个Object锁。await()、dosign()等方法就是让线程阻塞、加入队列、唤醒线程等。AQS框架下基本各种独占的加锁,解锁等操作到最后都是基于这个类实现的。该类是提供给子类去使用的,具体实现等下次说ReentranLock再深入了解。有人可能觉得为什么实现这个内部类,又不用,而是给子类去用,那为什么不放到子类去呢?其实答案,很简单,抽象加模板模式

p.s. 只有独占锁才能配合该类使用。

AQS的成员函数

AQS的公用的方法,主要是加锁与解锁方法。以下方法只提供了模板,部分实现还是在子类当中,直接调用会抛出异常。

acquire()

尝试获取锁,失败则进入队列。

先执行tryAcquire()(子类实现),成功则直接返回,如果是获取锁失败,则执行addWaiter(),通过CAS在双向链表的尾部添加一个新独占节点。

然后把节点丢到acquireQueued()中执行。该方法其实就是自旋尝试获取锁或阻塞线程(子类实现决定)。一开始,获取新节点的前驱节点,如果这个节点是head,则证明只有两个节点,此时再次执行tryAcquire()尝试获取锁,若获取成功,则不需要中断,成功结束。

如果还是获取失败,则执行shouldParkAfterFailedAcquire(),根据前驱节点状态(子类设值)判断是否继续自旋(当waitStatus为初始值,重复上一步,直到前面的节点一直在减少到前驱节点为head)或者阻塞线程(当waitStatus标记为SIGNAL)

最后如果acquireQueued()返回需要阻塞,则执行selfInterrupt()设置线程为中断

可以看回acquire()函数的写法,十分的艺术。利用条件判断的短路规则,实现在if()条件内嵌套判断执行语音。一般人(笔者本人)如果要实现这个功能,会这么写

所以下次遇到类似嵌套if条件判断的语句,可以学习下acquire()的这种短路写法。赞

Java多线程——AQS框架源码阅读的更多相关文章

  1. Java多线程类FutureTask源码阅读以及浅析

    FutureTask是一个具体的实现类,实现了RunnableFuture接口,RunnableFuture分别继承了Runnable和Future接口,因此FutureTask类既可以被线程执行,又 ...

  2. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

  3. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  4. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  5. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  6. CI框架源码阅读笔记2 一切的入口 index.php

    上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...

  7. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  8. AbstractQueuedSynchronizer AQS框架源码剖析

    一.引子 Java.util.concurrent包都是Doug Lea写的,来混个眼熟 是的,就是他,提出了JSR166(Java Specification RequestsJava 规范提案), ...

  9. CI框架源码阅读笔记1 - 环境准备、基本术语和框架流程

    最开始使用CI框架的时候,就打算写一个CI源码阅读的笔记系列,可惜虎头蛇尾,一直没有行动.最近项目少,总算是有了一些时间去写一些东西.于是准备将之前的一些笔记和经验记录下来,一方面权作备忘,另一方面时 ...

随机推荐

  1. 解决“并非来自 Chrome 网上应用店。”

    Chrome谷歌浏览器已停用不支持的扩展程序解决方法 第一种方法:(亲测有效) 1.首先把需要安装的第三方插件,后缀.crx 改成 .rar,然后解压,得到一个文件夹 2.再打开chrome://ex ...

  2. bzoj 5094 [Lydsy1711月赛]硬盘检测 概率dp

    [Lydsy1711月赛]硬盘检测 Time Limit: 1 Sec  Memory Limit: 256 MBSubmit: 273  Solved: 75[Submit][Status][Dis ...

  3. django返回二进制图片

    @login_required def down_img(request, path): content = Storage().download(path) from django.http imp ...

  4. python自带的线程池和进程池

    #python自带的线程池 from multiprocessing.pool import ThreadPool #注意ThreadPool不在threading模块下 from multiproc ...

  5. java中 快捷键输入System.out.println();

    syso 然后:alt+ /(就是问号键)

  6. camera摄像原理之四:曝光和GAMMA【转】

    转自:http://blog.csdn.net/ghostyu/article/details/7912880 从最明亮到最黑暗,假设人眼能够看到一定的范围,那么胶片(或CCD 等电子感光器件)所能表 ...

  7. 冒泡排序的思想 python 冒泡排序、递归排序

    冒泡排序的时间复杂度是O(N^2) 冒泡排序的思想: 每次比较两个相邻的元素, 如果他们的顺序错误就把他们交换位置 比如有五个数: 12, 35, 99, 18, 76, 从大到小排序, 对相邻的两位 ...

  8. springboot 整合springDataJPA

    springboot 整合springDataJPA 〇.搭建springboot环境 一.添加依赖 mysql <!-- mysql驱动 --> <dependency> & ...

  9. zabbix mysql自动发现规则

    1.配置mysql,添加监控用的账号,授予查看所有用户线程/连接的权限 GRANT PROCESS ON *.* TO 'zabbix'@'127.0.0.1' identified BY '20c1 ...

  10. PHP定时执行

    参考一 test.bat D:\myamp\php\php.exe -q D:\myamp\Apache\htdocs\dingshi.php dingshi.php <?php ignore_ ...