1、什么是AQS?
AQS全称,AbstractQueuedSynchronizer,意思大概就是“抽象队列同步器”,这个名词有点抽象,我们来先看看源码中的介绍,lalalalala…..,一大段英文。
/**
* Provides a framework for implementing blocking locks and related
* synchronizers (semaphores, events, etc) that rely on
* first-in-first-out (FIFO) wait queues. This class is designed to
* be a useful basis for most kinds of synchronizers that rely on a
* single atomic {@code int} value to represent state. Subclasses
* must define the protected methods that change this state, and which
* define what that state means in terms of this object being acquired
* or released. Given these, the other methods in this class carry
* out all queuing and blocking mechanics. Subclasses can maintain
* other state fields, but only the atomically updated {@code int}
* value manipulated using methods {@link #getState}, {@link
* #setState} and {@link #compareAndSetState} is tracked with respect
* to synchronization.
* */
翻译过来大概就是:
1、AQS是一个用于实现阻塞锁和相关同步器 (semaphores, events等等)的框架,它是基于FIFO等待队列的;
2、AQS是“以单个原子值(int)表示状态的同步器”的基础;
3、子类必须定义protected的方法来改变状态,还必须根据这个对象被acquired或released来定义状态的含义,且只能通过getState()、setState()、compareAndSetState()来更新状态值。
2、AQS的组成
这里没也什么好说的,与其说一大堆不如直接上源码看组成
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
private static final long serialVersionUID = 7373984972572414691L;
//构造方法
protected AbstractQueuedSynchronizer() { }
//定义了一个静态内部类Node
//AQS内部维护了一个CLH队列,Node是这个队列的节点
static final class Node {...}
//队列头指针
private transient volatile Node head;
//队列尾指针
private transient volatile Node tail;
//状态位
private volatile int state;
//一大堆方法.....
}
3、AQS中的CLH队列
关于CLH队列,有个很有趣的地方,我以为CLH是三个英文单词的缩写,但说明里是这样写的——”CLH” (Craig, Landin, and Hagersten),应该是三个大佬的名字。
源码中的说明翻译过来就是: AQS中的等待队列是CLH阻塞队列的变种,CLH的锁常用于自旋锁。相反,我们使用它们来阻塞同步器,但使用相同的基本策略来hold住前节点(prev)的控制信息。每个节点中的“状态”字段跟踪线程是否应该被阻塞。
对于这里,我的理解是AQS中的CLH队列并没有使用自旋锁,而是用状态值来判断线程是否应该被阻塞。(如果理解错了希望广大网友可以纠正)
下面我们来分析CLH的节点类:
“`
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;
//下面是几个表示状态的常量:
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should unconditionally propagate
*/
static final int PROPAGATE = -3;
/**
* Status field, taking on only the values:
* SIGNAL: 此节点的后继通过park()被阻塞,当其释放或取消时,必须unpark()他的后继;
* 为了防止冲突,获取方法必须首先指示他们需要一个信号,然后重试原子获取;
* 在失败时,进行阻塞。这个状态就是上面提到的信号。
*
* CANCELLED: 结点被由于超时或中断被撤销,且再也无法离开这个状态;
*
* CONDITION: 结点在条件队列中,因为等待某个条件而被阻塞;它将不被用作同步队列节
* 点,直到状态值改变为0;
*
*
* PROPAGATE: 大概意思是这是保证下一次可以直接传播的状态
* 0: 除以上状态外的状态
*
*
* 结点初始化时,waitStatus位为0, 要使用CAS进行修改。
*/
volatile int waitStatus;
//前指针
volatile Node prev;
//后指针
volatile Node next;
//进入队列的线程
volatile Thread thread;
//条件队列中的下一个结点
Node nextWaiter;
//一大堆方法....
}
由源码可知,CLH队列的形状大概是像下面这个样子
Java并发编程从入门到精通(三)-AQS源码分析(方法解析篇)将在不久后完笔