AQS源码分析
前言
AQS是整个JUC的基石,全称为AbstractQueuedSynchronizer,中文翻译为抽象队列同步器
AQS是一个抽象类,运用的设计模式是抽象模版模式,有许多的锁和同步器实现了AQS
其中ReentrantLock就实现了AQS,这里以ReentrantLock为例来剖析AQS
ReentrantLock内部结构
ReentrantLock类实现了Lock接口
ReentrantLock中有一个抽象的静态内部类Sync,这个sync继承了AbstractQueuedSynchronizer
sync下面有两个实现类
分别为NonfairSync和fairSync
NonfairSync用于实现ReentrantLock非公平锁功能
FairSync用于实现ReentrantLock公平锁功能
ReentrantLock的主要功能是由这个静态内部类Sync实现的
ReentrantLock中有一个成员变量sync,ReentrantLock的方法最终是通过调用这个sync成员变量实现的
而ReentrantLock是非公平锁还是公平锁最终看sync接收的是NonfairSync对象还是FairSync对象
用一张图来概括以上关系
ReentrantLock构造方法
ReentrantLock有两个构造方法
分别如下所示
无参构造
默认为非公平锁
有参构造
根据传入的fair值选择公平锁还是非公平锁
true则为公平锁,false则为非公平锁
lock方法源码分析
FairSync和NonfairSync的lock方法有差别
FairSync的lock方法
NonfairSync的lock方法
其中acquire方法为AQS的final方法
acquire方法首先调用的是tryAcquire方法
tryAcquire方法如下
此方法为AQS的一个钩子函数,交由子类实现
由于子类FairSync和NonfairSync的实现都不一样,所以这里以非公平锁来举例
这里以如下一段程序举例
A,B,C三个线程同时争抢ReentrantLock锁,由于抢夺有先后顺序,所以我们可以通过调试看到AQS的内部执行流程
1 |
|
ReentrantLock内部维护了一个改进的双向CLH队列,同时维护了一个状态量state,这个state用于表示当前队列的状态,这个队列被称为等待队列
队列的每一个元素都是Node类型,基本结构如下
现在开始Debug
首先state=0,表示等待队列处于空闲状态
然后ReentrantLock会调用sync.lock()方法进行上锁
由于默认是非公平锁,所以进入到NonfairSync的lock方法中
首先会尝试进行一次CAS抢占锁操作
可以看到compareAndSetState方法就是通过CAS尝试设置state=1达到上锁效果
底层是通过unsafe类实现的,这里不做深究
由于此时state=0,s所以此时compareAndSetState设置state=1成功,成功进入if语句块里面
接下来会调用setExclusiveOwnerThread将当前线程设置为独占线程
exclusiveOwnerThread是AQS的一个成员变量,用于记录当前等待队列中的独占线程
至此,第一个线程就成功抢占锁资源
接下来我们观察第二个线程的运行情况
CAS失败,进入acquire方法
acquire方法如下
执行tryAcquire方法
进入nonfairTryAcquire方法
此时state又变为0,表示当前队列中的线程已经将锁释放,多线程环境,调试过程中其他线程也在执行,所以这个方法也要进行CAS获取锁操作
可以看到此时控制台已经输出
可以看到获取锁成功,返回true
回到acquire方法
由于获得锁的线程执行很快,因此第三个线程执行的操作和第二个线程执行的操作一样。。。
还有两个重要方法acquireQueued和addWaiter程序没有执行到
因此下面分析下这两个方法的作用
addWaiter方法
addWaiter方法主要用于添加等待线程到等待队列中去
1 |
|
acquireQueued方法
1 |
|