AQS
更多干货尽在 一行一行源码分析清楚AbstractQueuedSynchronizer
一. 概述
- 为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。
- 此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。
- 子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。
1.1 使用
为了将此类用作同步器的基础,需要适当地重新定义以下方法:
1.2 AQS基本属性
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { private static final long serialVersionUID = 7373984972572414691L; // 头节点,表示当前持有锁的线程 private transient volatile Node head; // 阻塞队列的尾节点,每个新的节点进来,都插入到最后,也就形成了一个隐视的链表 private transient volatile Node tail; // 代表当前锁的状态, // 0代表没有被占用, // 大于0代表有线程持有当前锁,之所以说大于0,而不是等于1,是因为锁可以重入嘛,每次重入都加上1 private volatile int state; // 代表当前持有独占锁的线程,举个最重要的使用例子,因为锁可以重入.reentrantLock.lock()可以嵌套调用多次 // 所以每次用下面这个条件来判断当前线程是否已经拥有了锁 // if (currentThread == getExclusiveOwnerThread()) {state++} private transient Thread exclusiveOwnerThread; //继承自AbstractOwnableSynchronizer }
1.3 阻塞队列
AbstractQueuedSynchronizer 的等待队列示意如下所示,注意了,之后分析过程中所说的 queue,也就是阻塞队列不包含 head,不包含 head,不包含 head
等待队列中每个线程被包装成一个 node,数据结构是链表
static final class Node { // 标识节点当前在共享模式下 static final Node SHARED = new Node(); // 标识节点当前在独占模式下 static final Node EXCLUSIVE = null; // ======== 下面的几个int常量是给waitStatus用的 =========== // 代码此线程取消了争抢这个锁 static final int CANCELLED = 1; // 官方的描述是,其表示当前node的后继节点对应的线程需要被唤醒 static final int SIGNAL = -1; // 表示在条件队列中 static final int CONDITION = -2; // 同样的不分析,略过吧 static final int PROPAGATE = -3; // ===================================================== // 取值为上面的1、-1、-2、-3,或者0(以后会讲到) // 这么理解,暂时只需要知道如果这个值 大于0 代表此线程取消了等待, // 也许就是说半天抢不到锁,不抢了,ReentrantLock是可以指定timeouot的。。。 volatile int waitStatus; // 前驱节点的引用 volatile Node prev; // 后继节点的引用 volatile Node next; // 这个就是线程本尊 volatile Thread thread; }
如果文章对您有所帮助,可以点一下推荐