其实一开始是想接着写java锁的,不过后面发现内置锁和其他同步器基本都离不开AQS。既然AQS绕不过去,那只好就开始探究一下AQS了,AQS即AbstractQueuedSynchronizer,其支持的操作简单的说包括:阻塞和非阻塞的同步;可选的超时;通过中断实现取消以及定义了Condition接口。为了实现这些功能,我们需要对同步状态进行原子管理,线程阻塞和释放,队列的管理。下面会进行简单的说明。
- 状态管理
用一个volatile的int表示状态,提供getState,setState以及CompareAndSetState方法进行状态管理。 - 阻塞
通过LockSupport.park()和LockSupport.unpark()实现线程的阻塞和释放。LockSupport类用于创建锁和其他同步工具类的基本线程阻塞原语。park操作是不可重入的,类似于二值信号量,如果先unpark再park线程不会阻塞,且park可以被中断。 - 队列管理
AQS中定义了Node类,每个Node有各自的状态并且维护了一个prev和一个next用以形成队列结构。AQS保存了一个head节点和一个tail节点。形成的等待队列实际上可以理解为是CLH锁队列的一个变种。
CLH经常用于自旋锁,其维护了一个节点,node中用locked表示线程状态,如果true则表示正在申请锁或者已经得到锁,false则表示已经释放锁。在lock方法中节点将检查前驱节点的locked状态,如果为true则继续进入循环直到前驱节点为false标记自己释放了锁。unlock操作则需要将locked置为false。
在AQS中,节点的状态不用于控制自旋而是用来控制阻塞。当前面节点release的时候,当前节点应当被唤醒。
有了这些说明,大家对AQS应该有了一个基本的了解,在后面的文章中,我会对AQS中的重要方法进行解释说明。