[整理] AQS 基础
Lock的子类实现都是基于AQS的。
一、AQS是什么?
首先我们来普及一下juc是什么:juc其实就是包的缩写(java.util.concurrnt)
- 不要被人家唬到了,以为juc是什么一个牛逼的东西。其实指的是包而已~
我们可以发现lock包下有三个抽象的类:
- AbstractOwnableSynchronizer
- AbstractQueuedLongSynchronizer
- AbstractQueuedSynchronizer
通常地:AbstractQueuedSynchronizer简称为AQS
我们Lock之类的两个常见的锁都是基于它来实现的:
那么我们来看看AbstractQueuedSynchronizer到底是什么,看一个类是干什么的最快途径就是看它的顶部注释
通读了一遍,可以总结出以下比较关键的信息:
- AQS其实就是一个可以给我们实现锁的框架
- 内部实现的关键是:先进先出的队列、state状态
- 定义了内部类ConditionObject
- 拥有两种线程模式
- 独占模式
- 共享模式
- 在LOCK包中的相关锁(常用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建
- 一般我们叫AQS为同步器
二、简单看看AQS
上面也提到了AQS里边最重要的是状态和队列,我们接下来就看看其源码是怎么样的…
2.1同步状态
使用volatile修饰实现线程可见性:
修改state状态值时使用CAS算法来实现:
2.2先进先出队列
这个队列被称为:CLH队列(三个名字组成),是一个双向队列
看看它队列源码的组成:
static final class Node {
// 共享
static final Node SHARED = new Node();
// 独占
static final Node EXCLUSIVE = null;
// 线程被取消了
static final int CANCELLED = 1;
// 后继线程需要唤醒
static final int SIGNAL = -1;
// 等待condition唤醒
static final int CONDITION = -2;
// 共享式同步状态获取将会无条件地传播下去(没看懂)
static final int PROPAGATE = -3;
// 初始为0,状态是上面的几种
volatile int waitStatus;
// 前置节点
volatile Node prev;
// 后继节点
volatile Node next;
volatile Thread thread;
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
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;
}
}
2.3acquire方法
获取独占锁的过程就是在acquire定义的,该方法用到了模板设计模式,由子类实现的~
过程:acquire(int)尝试获取资源,如果获取失败,将线程插入等待队列。
插入等待队列后,acquire(int)并没有放弃获取资源,而是根据前置节点状态状态判断是否应该继续获取资源,如果前置节点是头结点,继续尝试获取资源,如果前置节点是SIGNAL状态,就中断当前线程,否则继续尝试获取资源。
直到当前线程被park()或者获取到资源,acquire(int)结束。
来源:
2.4release方法
释放独占锁的过程就是在acquire定义的,该方法也用到了模板设计模式,由子类实现的~
过程:首先调用子类的tryRelease()方法释放锁,然后唤醒后继节点;
在唤醒的过程中,需要判断后继节点是否满足情况,如果后继节点不为且不是作废状态,则唤醒这个后继节点,否则从tail节点向前寻找合适的节点,如果找到,则唤醒.
来源:
三、最后
总结一下AQS到底是什么吧:
-
juc包中很多可阻塞的类都是基于AQS构建的
- AQS可以说是一个给予实现同步锁、同步器的一个框架,很多实现类都在它的的基础上构建的
-
在AQS中实现了对等待队列的默认实现,子类只要重写部分的代码即可实现(大量用到了模板代码)