AQS(AbstractQueuedSynchronizer)
上一期,我们介绍了乐观锁,而乐观锁的本质即是CAS,操作系统提供了支持CAS修改内存值的原子指令,所以乐观锁得以实现。从软件工程的角度去看,虽然底层已经通过CAS实现了乐观锁,Java的底层已经在Unsafe这个类中封装了compareAndSwap方法,支持了对CAS原语的调用,为了使上层更加易用,需要经过进一步的抽象和封装。抽象这个词虽然简单,但私以为要做出高内聚低耦合的抽象绝对是难点。在Java中最著名的并发包就是JUC,其中的组件和日常Java开发息息相关。
在JUC中,最核心的组件便是AQS。可以这么理解,AQS是对CAS的一种封装和丰富,AQS引入了独占锁、共享锁等性质。基于AQS,JUC中提供了更多适用于各种预设场景的组件,当然你也可以基于AQS开发符合自身业务场景的组件。所以,AQS作为承下启上的重点,我们需要仔细来看。
队列同步器AQS是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。
1、AQS成员属性:
private volatile int state;
state就是用于判断共享资源是否正在被占用的标记位。
为什么是int类型而不是boolean类型呢?
这是由于AQS是支持独占和共享两种加锁模式的,那么在共享模式下,state可以用来记录线程占用的数量。
private transient volatile Node head;
private transient volatile Node tail;
AQS中存在一个队列用于对等待线程进行管理,这个队列通过一个FIFO的双向链表来实现。head 和 tail 变量表示这个队列的头尾。
FIFO双向链表:
2、AQS内部类:
队列中每个节点的类型就是内部类Node
static final class Node {
/** Marker to indicate a node is waiting in shared mode */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
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;
}
}
Node中主要存储了线程对象(thread)、节点在队列里的等待状态(waitStatus)、前后指针
(prev、next)等信息。这里需要重点关注的是waitStatus这个属性,它是一个枚举值,AQS工作时必然伴随着Node的waitStatus值的变化,如果理解了waitStatus变化的时机,那对理解AQS整个工作原理有很大的帮助。
waitStatus主要包含四个状态:
▲0,节点初始化默认值或节点已经释放锁
▲CANCELLED为1,表示当前节点获取锁的请求已经被取消了
▲SIGNAL为-1,表示当前节点的后续节点需要被被唤醒
▲CONDITION为-2,表示当前节点正在等待某一个Condition对象,和条件模式相关
▲PROPAGATE为-3,传递共享模式下锁释放状态,和共享模式相关