前言
在之前的文章《Java 基本功 之 CAS》中介绍了CAS的概念以及原理,今天来介绍 Java concurrent.locks 包 中的基础组件AQS - AbstractQueuedSynchronizer类。看到这里,也许你会感到些许陌生,心想:这家伙是干啥的?怎么从来没见过?能用来干什么?别急,下面一一解惑。
AQS 简介
AQS(AbstractQueuedSynchronizer) 是 Java concurrent lock 包中最基础的组件。最常见 ReentrantLock 锁就是在其基础上实现的,我们知道 ReentrantLock 有以下几个特性:
公平,非公平模式。
可重入性。
…
那么,这些特性在底层是如何实现的呢?
首先我们来看 ReentrantLock 类图,如下:
图(1) ReentrantLock 类图
解释:
通过上述类图,我们知道:在 ReentrantLock 中:有 FairSync (实现公平锁), NofairSync (实现非公平锁)。而其两者均继承自Sync类,Sync 类又继承自AbstractQueuedSynchroizer。AbstractQueuedSynchroizer 接口继承 AbstractOwnableSynchroinzer 以及实现 Serializable 接口。
代码如下所示:
NonfairSync 类源码如下所示:
FairSync 类源码如下所示:
无论是 NonfairSync 还是 FairSync 类,在其 lock 方法中,均有 acquire() 方法,该方法是其父类AbstractQueuedSynchronizer中的方法,源码如下所示:
解释:
tryAcquire 方法为抽象方法,由其子类进行实现,其含义为独享锁获取, true 表示获取成功。
addWaiter 方法表示添加一个 EXCLUSIVE 模式的 Node 节点到队列中,并返回当前节点。
acquireQueued 表示在队列中循环获取锁。
以 FairSync 锁为例,其 tryAcquire 函数其实现如下所示:
addWaiter 代码如下所示:
其中 enq 方法为添加Node到FIFO双向队列中
acquireQueued 代码如下所示:
selfInterupt 代码如下:
上面的代码并不多,但这恰恰就是 ReentrantLock 代码的实现,之所以这么简洁,其得益于底层的 AbstractQueuedSynchronizer 类。
源码
通过上面 ReentrantLock 源码的介绍,我们还是有些疑问,其中包括但不限于:
state 字段代表什么?
Node 节点 有哪些模式?
waitStatus 有哪些状态?
AQS 底层数据结构是怎样的?
…
下面我们一一进行介绍解答:
AQS 底层数据结构是CLH(Craig, Landin, and Hagersten) 变种的FIFO双向链表,AQS 类图如下所示:
图(2) AQS 类图
由于篇幅原因,没有显示完整的方法列表。如有兴趣的童鞋,可在源码中查看。
双向链表图, 如下所示:
图(3) 链表类图
其节点由其自定义的Node类构成,Node节点类图如下所示:
图(4) Node 类图
其中:
Node 模式有:
SHARED(共享), EXCLUSIVE (独占) 两种模式。
waitStatus 有以下几种状态:
state 字段表示持锁状态,0 表示未持锁,大于 0 表示持锁数,lock 则 增加 state 的值,unLock 则减少 state 的值,直至 state 为0 时,则unLock完成。
其中在AQS类初始化时,代码如下:
封装CAS方法:
结语
AQS 提供的是锁的基础组件,其用法由上层组装实现。其主要的子类有: ReentrantLock,CountDownLatch, Semaphore 也基于其自定义锁。
参考文章:
《JDK1.8 AbstractQueuedSynchronizer 的实现分析(上) 》
《JDK1.8 AbstractQueuedSynchronizer 的实现分析(下)》
《从ReentrantLock的实现看AQS的原理及应用》
《不得不说的Java琐事》
领取专属 10元无门槛券
私享最新 技术干货