并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer

对于AQS我们更多的是了解它,做到知其思想,明其原理,切记不要强求自己弄懂每一行代码,耗费的精力与收获可能不成正比。

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第1张图片

01.简介

AbstractQueuedSynchronizer类

简称:AQS,中文名:抽象同步队列

类的全路径如下:java.util.concurrent.locks.AbstractQueuedSynchronizer

小知识点:java.util.concurrent包在业界被简称为JUC,因此如果看到JUC.XXX那就是在讲java.util.concurrent包下的类

02.功能

实现同步器的基础类,同时也是并发包(JUC)中锁的底层实现类。

03.类图

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第2张图片

04.类图说明

1. AbstractOwnableSynchronizer是AQS的父类,里面只有一个Thread exclusiveOwnerThread字段,用来存储当前已经获得排它锁的对象

AbstractOwnableSynchronizer部分截图

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第3张图片

例:某线程已经使用ReentrantLock.lock获取锁成功,其他线程在当前线程释放锁之前都无法获得锁,这就是exclusive排他模式,而当前已经获得锁的线程就存储在exclusiveOwnerThread这个字段里)。

2. Node为AQS的内部类,AQS本质上是一个FIFO(先进先出)的双向队列,而队列中存放的元素就是Node对象。

AbstractQueuedSynchronizer.Node内部类部分截图

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第4张图片

3. ConditionObject也为AQS的内部类,用来实现带有条件的锁。例如ReentrantLock.newCondition()创建的条件锁,本质上创建的是AQS的ConditionObject内部类对象。

AbstractQueuedSynchronizer.ConditionObject内部类部分截图

4. Sync(同步器)、FairSync(公平锁同步器)、NonfairSync(非公平锁同步器)这都是AQS的实现类,比如ReentrantLock就是使用这3个类实现了公平锁与非公平锁特性。

ReentrantLock.Sync类部分截图

ReentrantLock.FairSync类部分截图

ReentrantLock.NonfairSync类部分截图

05.源码解读

AQS类中的字段如下

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第5张图片

1. AQS是一个FIFO(先进先出)的双向队列,队列中存储Node元素(Node中的thread变量用来存储进入AQS队列的线程对象),使用head和tail记录队首和队尾,next指向下一个Node。

2. state变量,对于不同的AQS实现类,它用来表示不同的含义(具体含义不用记忆)

ReentrantLock中 state用来表示当前线程获取的可重入次数。

ReentrantReadWriteLock中 state的高16位表示获取读锁的次数,低16位表示获取写锁的可重入次数。

Semaphore中 state表示当前可用的信号个数

CountDownlatch中 state表示计数器的当前值

3. AQS大量使用Unsafe类的底层方法实现,所以才会有unsafe、stateOffset、headOffset、tailOffset、waitStatusOffset、nextOffset这些字段。(Unsafe类的详细讲解可参见视频课程)

AQS.Node内部类中的字段如下

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第6张图片

1. thread用来记录进入AQS队列中的线程对象。

2. prev、next分别用于指向上一个和下一个队列元素。

3. SHARED标记该线程是获取共享资源时被阻塞进入AQS队列的

4. EXCLUSIVE用来标记线程是获取独占资源时被阻塞进入AQS队列的

5. waitStatus记录当前线程的等待状态,状态有以下几种:(具体含义不用记忆)

CANCELLED 线程被取消了

SIGNAL 线程需要被唤醒

CONDITION 线程在条件队列里等待

PROPAGATE 释放共享资源时需要通知其他节点

6. nextWaiter指向下一个等待执行条件的节点,与下方的ConditionObject相关。

AQS.ConditionObject内部类中的字段如下

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第7张图片

1. ConditionObject实质也是一个FIFO的队列,当某个condition的await方法被调用时,就会进入队列。相同的condition进入相同的队列。

2. 所以当某一个Lock产生多个condition的时候,就会产生多个condition队列。

Condition原理图

并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer_第8张图片

3. 当调用condition的signal方法时,队首的Node(也就是firstWaiter)出队列,Node中对应的线程开始执行。

4. 当调用condition的signalAll方法时,队列中的全部Node出队列,继续执行。

06.结语

理解AQS最好的方式是Debug代码,查看ReentrantLock锁以及ReentrantLock中Condition锁的运行方式

文章表达形式有限,如需深入快速学习并发编程,可学习Kevin录制《JAVA并发编程-豪华版》课程。(在网易云课堂搜索)

你可能感兴趣的:(并发编程 | 底层核心类AQS源码解读 AbstractQueuedSynchronizer)