
聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS
一、AQS是什么
- AQS全称AbstractQueuedSynchronizer即抽象队列同步器,可以理解成是一个可以实现锁的框架(基类,它可以实现共享和独占两种模式的锁,事实上juc包下很多关于锁的工具类也是基于AQS的;它提供了一些模板方法供子类实现拓展,并且本身结合底层的Unsafe类实现了基于cpu原语层的安全操作,从而实现在并发环境下的线程安全
二、AQS的实现原理
- AQS能作为基类来实现锁的功能主要原因来自于它维护的一个int类型的state变量和一个FIFO的双向队列;实现类可以根据自身的需求,通过控制state的值来决定线程是否需要阻塞,而双向队列用来存放没有争抢到锁资源的线程;并且AQS通过结合Unsafe类的能力封装了可以线程安全的操作state值的方法(一堆CAS的操作方法,这样程序员就可以只关注锁的使用而不必关注底层实现的细节了;
- AQS支持两种模式锁的实现,分别是独占锁和共享锁,独占锁的具体实现以ReentrantLock为代表,共享锁的实现诸如CountDownLatch、CyclicBarrier等
注:由于后续会介绍AQS的源码以及子类实现,所以这里只是大白话般的描述了一下AQS的原理,即两个关键:一个state一个双向队列,其实要展开还有许多细节要聊,考虑到这些细节后续源码里会有体现这里就不再表述了
三、AQS的源码简析
1、state变量
private volatile int state;
1、state是AQS提供的供子类拓展的一个同步状态,子类可以维护state的不同状态来实现不同效果的锁实现,如ReentrantLock就是通过维护state是否为0或1来表示锁的加解操作;
2、Node内部类
- Node类是双向CLH队列的构成元素,其维护的thread变量就是没有争抢到锁的线程,然后还维护了CLH队列的其他几个关键信息,如当前Node的前置节点(prev、后续节点(next等,下面贴上Node的源码
static final class Node {
/** 表示当前节点正处于共享模式 */
static final Node SHARED = new Node(;
/** 表示当前节点正处于独占模式 */
static final Node EXCLUSIVE = null;
/** waitStatus对应的值,表示线程已取消 */
static final int CANCELLED = 1;
/** waitStatus对应的值,指示后续线程需要取消标记*/
static final int SIGNAL = -1;
/** waitStatus对应的值,指示线程正在等待condition唤醒*/
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
/**
* 等待状态,枚举值有1,0,-1,-2,-3分别对应上面的几个变量值,0表示以上状态都不是
*/
volatile int waitStatus;
/**
* 当前Node的前置节点
*/
volatile Node prev;
/**
* 当前Node的后继节点
*/
volatile Node next;
/**
* 与当前Node绑定的被阻塞的线程
*/
volatile Thread thread;
/**
* 下一个等待节点,Condition状态下要用到
*/
Node nextWaiter;
/**
* 如果节点在共享模式下等待,则返回true。
*/
final boolean isShared( {
return nextWaiter == SHARED;
}
/**
* 获取当前队列的前置节点
*
* @return the predecessor of this node
*/
final Node predecessor( throws NullPointerException {
Node p = prev;
if (p == null
throw new NullPointerException(;
else
return p;
}
Node( { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
3、AQS供子类拓展的模板方法
独占模式供子类实现的方法
tryAcquire(int 尝试获取锁,获取成功返回true,失败返回false
共享模式供子类实现的方法
-
tryReleaseshared(int
tryAcquireshared(int
上面简单介绍了一下AQS的原理以及源码的部分注释,接下来我会写一篇ReentrantLock源码解读的相关文章,来体验下AQS的实际用处