AbstractQueuedSynchronizer(AQS)
概述
AbstractQueuedSynchronizer
(简称AQS)是Java中锁和同步器的基础框架,大多数的锁和同步器都是通过继承AQS
来实现的。AQS
提供了一个灵活的框架,使得开发者可以根据自己的需求来实现各种锁和同步器。本文将介绍AQS
的基本原理和实现细节。
基本原理
AQS
维护了一个state
(状态)属性和一个等待队列。state
用来表示同步状态,当state
为0时表示锁没有被占用,当state
不为0时表示锁已经被占用,state
的含义和具体使用方法是由子类定义的。等待队列则用来存储那些请求锁或者同步器的线程。
当一个线程请求锁或同步器时,如果此时state
为0,则表示当前线程可以获得锁或同步器,此时会将state
设置为1,表示当前锁或同步器已经被占用了。如果此时state
不为0,则表示此时锁或同步器正在被其他线程占用,此时当前线程会被加入到等待队列中,等待其他线程释放锁或同步器。
当其他线程释放了锁或同步器时,会唤醒等待队列中的一个线程,使其重新尝试获取锁或同步器。如果此时该线程又成功获取了锁或同步器,则该线程会从等待队列中移除。
实现细节
等待队列
AQS
的等待队列是一个双向链表,每个节点表示一个等待线程(或者称为Node
),Node
继承自AbstractQueuedSynchronizer
。下面是Node
的定义:
static final class Node {
// 共享模式
static final Node SHARED = new Node();
// 独占模式
static final Node EXCLUSIVE = null;
// waitStatus的值表示当前节点需要等待的状态
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() {
}
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
节点有以下属性:
等待队列的头节点是一个哑节点,不表示任何一个等待线程。当等待队列不为空时,队首节点表示正在占用同步器或者锁的线程,队列中剩下的节点表示正在等待获取同步器或者锁的线程。
等待队列的操作主要有以下几个:
-
enq(node)
:将一个节点加入等待队列的尾部。
-
addWaiter(mode)
:创建一个新的节点并加入到等待队列的尾部。mode
表示该节点的模式,可以是独占模式或共享模式。
-
setHead(node)
:设置等待队列的头节点。
-
unparkSuccessor(node)
:唤醒等待队列中最近的一个还未被取消的节点。在独占模式下,需要唤醒的节点是当前节点的后继节点;在共享模式下,需要唤醒的节点是等待队列中第一个未被取消的节点。
state属性
在AbstractQueuedSynchronizer
中,state
属性是一个volatile
类型的整数,用来表示同步状态。子类可以通过修改state
的值来实现自己的同步机制。
当state
为0时表示同步器或锁没有被占用,当state
不为0时表示同步器或锁已经被占用。在独占模式下,state
的值为1表示锁已经被占用,在共享模式下,state
的值表示正在使用锁的线程数。
state
的主要操作有以下几个:
-
getState()
:获取当前状态的值。
-
setState(newState)
:设置当前状态的值。
-
compareAndSetState(expect, update)
:原子性地将当前状态和expect
比较,如果相等则将其设置为update
,并返回true,否则返回false。
独占模式
AbstractQueuedSynchronizer
中的独占模式是最常用的同步机制之一,代表了Java中的锁。
我们来看一下ReentrantLock
是如何实现独占模式的。
ReentrantLock
ReentrantLock
是一个可重入的互斥锁,它支持公平锁和非公平锁。ReentrantLock
继承自AbstractQueuedSynchronizer
,在ReentrantLock
的构造方法中会调用AbstractQueuedSynchronizer
的构造方法来初始化state
属性和等待队列。