AQS分析第一篇(AQS是什么,有什么用,数据结构)

问题是最好的老师!

一、思考

第一篇并不深究AQS的实现原理,简单的解决以下几个问题,如果您可以轻松回答出以下问题,可跳过该篇。

  • 问题一:AQS是什么?其使用场景在哪里?

看过JUC源码的大概都了解ReetrantLock是借助AQS实现的,那么AQS到底提供了怎样的功能,除了ReetrantLock还有哪些地方用到了AQS。

  • 问题二:AQS的数据结构?

AQS的全名叫AbstractQueueSynchronizer,顾名思义,其是一个抽象类,且内部维护了一个队列,其主要目的跟同步有关,那么这是一个怎样的队列,该队列代表了什么,存储了什么。

二、源码分析 

  • 注释翻译

如同阻塞队列那篇博文一样,在不知道AQS设计初衷的情况下,先从注释找答案,注释翻译如下:

提供了一个依赖于先进先出等待队列数据结构的框架,其目的是为了实现阻塞锁和一些相关的同步工具。该类设计的初衷是成为一个有用的基类,为大多数同步工具提供服务,而这些同步工具都将依赖于一个原子性的整数值来代表状态。实现AQS的子类必须定义父类受保护的方法去改变这个状态,并定义该状态对于正在获取或释放的对象的含义。有了这些,该类中的其他方法执行所有排队和阻塞机制。子类可以维护其他状态属性,但是只有通过父类的getState(),setState(),compareAndSetState()方法去原子性的更新父类的state属性才被认为是有效的同步操作。

 继承AQS的子类应该被设计为一个非公开的内部类,起到辅助外部类实现同步属性的作用 。AQS本身不实现任何同步接口。相反,它定义了acquireInterruptibly等方法,这些方法可以被具体的锁和相关的同步器适当地调用,以实现它们的公共方法。

该类支持默认的独占模式或者共享模式,或者两者同时支持。当采用独占模式获取时,其他尝试获取的线程将不会成功。多线程采用共享模式同时获取可能会成功。这个类并不知道前面所讲的这种共享锁 和独占锁的差异,当一个共享模式获取成功,下一个线程(如果存在)也必须确定它是否可以同时获得。在不同模式上等待的线程将会共用同一个先进先出队列。通常实现AQS的子类只支持一种模式,但是也可以同时支持两种模式比如ReadWriteLock。实现AQS的子类如果只支持一种模式就没必要定义另一个模式的方式。

 该类定义了一个内嵌的ConditionObject类,该类可以被支持独占模式的子类(isHeldExclusively方法表明了是否当前线程独占,用当前getState的结果作为入参调用release方法将会完全释放对象,用给定的state的保存值调用accquire方法,最终会将对象恢复到其上一个状态)用作Condition的一个实现。除了AQS方法之外,没有其它方法会创建这样一个Condition的实现,所以如果不能满足此约束,就不要使用AQS。ConditionObject的行为当然还是取决于它的同步器实现的语义。

该类提供了内部队列的检索,检测以及监控方法。为Condtion对象也提供了类似的方法,这些可以根据需要导出到借助AQS实现同步的类中。 

该类序列化之后,只会存储state属性,所以反序列化之后,队列为空。如果子类需要支持序列化功能,需要自己定义readObject方法通过反序列化将state恢复到一个已知值。

  •  数据结构分析

为了搞清楚AQS的队列的数据结构,必然得先搞懂队列中每一个节点(Node)的数据结构。

Node属性:

//由此可以看出AQS维护的是一个双向队列,那么为什么其要维护一个双向队列呢,请看后文分析
volatile Node next;
volatile Node prev;

//AQS是一个并发同步框架,那么队列存储的数据必然是阻塞线程
volatile Thread thread;

//注释翻译中有写AQS支持独占和共享两种模式,先不讨论怎么实现的,从注释可知这两个字段代表如下:

//注意:这两个字段并不会指向新的引用(随着Node初始化进行初始化),所以一定是其他指针指向这两个节 
// 点,具体是谁指向它请看后文分析。这只是第一篇,我们先了解这个数据结构。
static final Node SHARED = new Node();//表明当前Node代表的线程以共享模式等待
static final Node EXCLUSIVE = null;//表明当前Node代表的线程以阻塞模式等待


//由于截止目前未看过相关对以下这几个字段的解释,所以先根据注释进行翻译

//该字段的取值详情请看下面
//其取值采用数值排列是为了简化应用,非负值表示当前节点不需要进行通知。因此大多数的代码不要检查特 
// 定的值,只需要检查符号(正负)即可。
//该属性初始值为0表示标准的同步节点,对于普通同步节点,该值初始化为0,对于Condition节点,该字段 
// 初始化为CONDITION(-2)。一般使用CAS(或者在可能的情况下,无条件的volatile写)修改其值
 volatile int waitStatus;

//指向下一个在某个条件上等待的节点。或者指向一个特殊的值SHARED,前面我们分析过,SHARED字段必定有 
//某个引用指向它,在这里得到证实,即nextWaiter会指向SHARED,那么我们是否可以理解为只要当前节点的 
// nextWaiter为SHARED,就标识当前节点以共享模式等待呢,这里只是猜测,等分析源码进行论证,还要论 
// 证其是否会指向EXECLUSIVE从而标识当前节点以独占模式等待。
// Node nextWaiter;


//waitStatus取值(这里只是根据注释翻译一下,具体什么意思,等待后续源码分析中看起实际作用才知道):
//前面有了解到其取值以数值排列简化应用,这里可以看到其具体数值是多少。
//标识当前线程已经取消等待或者叫阻塞
static final int CANCELLED =  1;
//表明当前节点的下一个节点所代表的线程需要被唤醒
static final int SIGNAL    = -1;
//表明当前线程在等待某个条件而阻塞
static final int CONDITION = -2;
//表明当前线程下一次通过accquieShared获取资源时应无条件传播(这里的传播是什么意思,后面深入源码 
// 再理解),这里暂时这样翻译,不知道对不对,因为还未读过源码。
static final int PROPAGATE = -3;

在了解了Node的数据结构之后,我们再来分析AQS的数据结构:

AQS存在两个属性:

//注释中已经提到AQS的实现基于FIFO队列,所以必然有队头和队尾节点,那么AQS采用的是单向还是双向队列 
// 呢,请看后文分析(深入源码之后)。


//队列的头部,使用懒汉式方式进行初始化。除了初始化之外,该值只能通过setHead方法进行修改。注意:如果 
//head存在(不为空),它的waitStatus一定要保证不为CANCELLED(为什么这样限制,后续源码深入分析)。 
//但是通过前面分析,我们知道waitStatus非负代表其不通知,CANCELLED为1,那么这里是否可以理解为头结点 
// 一定会通知(唤醒)后续节点,待后续论证。但是稍稍看了源码的都知道head的初始化只是new了一个新的 
//Node,并未代表任何线程,初始化时其waitStatus为0(所有Node初始化时都为0),而waitStatus非负代表 
//其不通知,那么我们猜测看定会有某个方法会设置Node的waitStatus为负数,从而通知(唤醒)后面的线程, 
//关于这一点也需要论证


private transient volatile Node head;

//队列的尾节点,只能通过enq方法增加一个新的等待节点去修改它
private transient volatile Node tail;

至此我们可以大概画出AQS的数据结构,如下:

 AQS分析第一篇(AQS是什么,有什么用,数据结构)_第1张图片

三、回答开篇 

  • 问题一:AQS是什么?其使用场景在哪里?

答:AQS是一个同步框架,通过维护一个int类型的变量state和一个先进先出队列,实现共享资源的访问控制和线程阻塞,其提供了一些基类实现排队和阻塞机制,子类可以通过继承AQS并重写其提供的抽象类实现一个同步工具,同步工具的语义由子类决定。在JUC包下,通过AQS实现的同步工具类包含以下几个,我们并发工具类源码分析系列会一一分析:

  1. ReentantLock
  2. ReentantReadWriteLock
  3. Semaphore
  4. CountDownLatch
  5. Worker(ThredPoolExecutor类中)
  • 问题二:AQS的数据结构?

答:详情请看上文中数据结构分析。

本文就到这里,下一篇会介绍AQS的使用方式。

-------------------------------------------------------------------------------------------------------------------

知其然,更要知其所以然...

-------------------------------------------------------------------------------------------------------------------

 

你可能感兴趣的:(杂记---并发)