AQS是jdk中锁机制的重要框架,我们在通过继承AQS,进行队列的操作时,方法的作用位置大体如下:
Api中对该类的描述如下:
为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()、setState(int) 和 compareAndSetState(int, int) 方法来操作以原子方式更新的 int 值。
应该将子类定义为非公共内部帮助器类,可用它们来实现其封闭类的同步属性。类 AbstractQueuedSynchronizer 没有实现任何同步接口。而是定义了诸如 acquireInterruptibly(int) 之类的一些方法,在适当的时候可以通过具体的锁和相关同步器来调用它们,以实现其公共方法。
此类支持默认的独占模式和共享模式之一,或者二者都支持。处于独占模式下时,其他线程试图获取该锁将无法取得成功。在共享模式下,多个线程获取某个锁可能(但不是一定)会获得成功。此类并不“了解”这些不同,除了机械地意识到当在共享模式下成功获取某一锁时,下一个等待线程(如果存在)也必须确定自己是否可以成功获取该锁。处于不同模式下的等待线程可以共享相同的 FIFO 队列。通常,实现子类只支持其中一种模式,但两种模式都可以在(例如)ReadWriteLock 中发挥作用。只支持独占模式或者只支持共享模式的子类不必定义支持未使用模式的方法。
此类通过支持独占模式的子类定义了一个嵌套的 AbstractQueuedSynchronizer.ConditionObject 类,可以将这个类用作 Condition 实现。isHeldExclusively() 方法将报告同步对于当前线程是否是独占的;使用当前 getState() 值调用 release(int) 方法则可以完全释放此对象;如果给定保存的状态值,那么 acquire(int) 方法可以将此对象最终恢复为它以前获取的状态。没有别的 AbstractQueuedSynchronizer 方法创建这样的条件,因此,如果无法满足此约束,则不要使用它。AbstractQueuedSynchronizer.ConditionObject 的行为当然取决于其同步器实现的语义。
此类为内部队列提供了检查、检测和监视方法,还为 condition 对象提供了类似方法。可以根据需要使用用于其同步机制的 AbstractQueuedSynchronizer 将这些方法导出到类中。
此类的序列化只存储维护状态的基础原子整数,因此已序列化的对象拥有空的线程队列。需要可序列化的典型子类将定义一个 readObject 方法,该方法在反序列化时将此对象恢复到某个已知初始状态。
既然是基于队列的实现,我们先来看看其结点是怎么构成的:
等待队列中的结点-Node
等待队列是“CLH”(Craig,Landin和Hagersten)锁定队列的变体。 CLH锁通常用于自旋锁。我们使用它们替代阻塞同步器,但是使用相同的基本策略来保存关于其节点的前驱中的线程的一些控制信息。每个节点中的“状态”字段跟踪线程是否应该阻塞。在其前导结点释放时,将发出节点信号。队列中的每个节点都用作保存单个等待线程的特定通知监视器。但是,status字段不会控制线程是否拥有锁等。线程可能会尝试获取它是否在队列中的头部。但是并不能保证成功;它只给予竞争的权利。因此,当前释放的竞争者线程可能需要重新等待。要进入CLH锁,要将其进行原子拼接成为新尾部。要出列,您只需设置头部字段即可。
插入CLH队列只需要对“尾部”进行单个原子操作,因此存在未入队列和已入队列的简单原子划分点。同样,出列只涉及更新“头部”。然而,节点需要更多的工作来确定他们的后继结点是谁,部分是为了处理由于超时和中断而可能取消的结点。“prev”链接(未在原始CLH锁中使用)主要用于处理取消的结点。如果节点被取消,则其后继者(通常)重新链接到未取消的前导结点。有关自旋锁的类似机制的解释,请参阅Scott和Scherer的论文,网址为http://www.cs.rochester.edu/u/scott/synchronization/
我们还使用“next”链接来实现阻塞机制。每个节点的线程id保存在自己的节点中,因此前驱者通过遍历后继结点来通知后继节点以确定它是哪个线程。后继者的确定必须避免使用新排队节点的竞争来设置其前导的“下一个”字段。必要时通过在节点的后继者看起来为空时从原子更新的“尾部”向后检查来解决这个问题。(或者,换句话说,下一个链接是一个优化,因此我们通常不需要向后扫描。)
取消操作为基本算法引入了一些保守性。由于我们必须轮询取消其他节点,我们可能会忽略已取消的节点是在我们前面还是在我们后面。这是通过取消后始终停顿的后继节点来处理的,这使得他们能够稳定在新的前导结点上,除非我们能够确定一个将承担此责任的未取消的前导结点。
CLH队列需要一个虚拟标头节点才能启动。但是我们不会在构造函数中创建它们,因为如果没有被争用就会浪费资源。相反,在第一次争用时构造节点并设置头尾指针。
等待条件的线程使用相同的节点,但使用其他链接。条件只需要链接在简单(非并发)链接队列中的节点,因为它们仅在独占锁时才被访问。调用await时,将节点插入条件队列。调用signal时,节点被转移到主队列。状态字段的特殊值用于标记节点所在的队列。它的代码如下:
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;
/** 表示线程在等待条件的状态值*/
static final int CONDITION = -2;
/**
* waitStatus值表示下一个acquireShared应无条件传播
*/
static final int PROPAGATE = -3;
/**
* 等待状态.
*/
volatile int waitStatus;
/**
*链接到当前节点/线程依赖的前导节点以检查waitStatus。 在入队时分配,并且只在出列时才被排除。 此外,在取消前导结点时,我们在找到未取消的一个结点时将短路,前导结点将永远存在,因为头节点永远不会被取消:节点由于成功获取而变为头节点。 取消的线程永远不会成功获取,并且线程仅取消自身,而不取消任何其他节点.
*/
volatile Node prev;
/**
*链接到当前节点/线程在释放时取消驻留的后继节点。在入队列时进行分配,在绕过取消的前导结点时进行调整,并在出列时被排除.
*/
volatile Node next;
/**
* 操作结点的线程. 在构造函数中初始化,在使用完毕后无效
*/
volatile Thread thread;
/**
*链接到等待条件的下一个节点,或特殊值SHARED。因为条件队列只有在处于独占模式时才被访问,所以我们只需要一个简单的链接队列来在节点等待条件时保存节点。然后将它们转移到队列中以重新获取。并且因为条件只能是独占的,所以我们通过使用特殊值来表示共享模式的字段。*/
Node nextWaiter;
/**
*如果结点在共享模式中处于等待返回true
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
*返回上一个节点,如果为null则抛出NullPointerException。 在前导节点不为null时使用。 可以省略空检查,但是存在以帮助VM。
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { //用于建立初始头或SHARED标记
}
Node(Thread thread, Node mode) { // 用于添加等待者使用
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { //用于条件队列使用
this.waitStatus = waitStatus;
this.thread = thread;
}
}
结点中定义了一些状态值表示当前结点的线程所处的状态:
SIGNAL(-1) | 此节点的后继结点需要等待,因此当前节点在释放或取消时必须取消其后继。 为避免竞争,获取方法时必须首先指明它们需要等待,然后重试原子获取,且在失败时阻止。 |
CANCELLED(1) | 由于超时或中断,此节点被取消。 节点永远不会离开这个状态。 特别要注意的是,具有已取消节点的线程永远不会再次阻塞。 |
CONDITION(-2) | 此节点当前处于条件队列中。在传输之前,它不会用作同步队列中的节点,此时状态将设置为0.(此处使用此值与该字段的其他用途无关,但简化了机制。) |
PROPAGATE(-3) | releaseShared应该传播到其他节点。 在doReleaseShared中设置(仅限头节点)以确保继续传播,即使其他操作已经介入。 |
0 | 上面情况都不是。 |
这些值以数字方式排列以简化使用。非负值意味着节点不需要发信号。 因此,大多数代码不需要检查特定值,仅使用符号。对于正常同步节点,字段初始化为0,对于条件节点,字段初始化为CONDITION。 此状态使用CAS(或可能的情况下,无条件的易失性写入)进行修改。
一个结点包括一个线程,一个condition等待队列,以及线程的等待状态。同时包含节点的前导结点和后继节点。
获取字段偏移量
为支持CAS操作进行设置. 我们需要在这里原生实现:为了允许以后对其进行继承重写,我们不能显式地继承AtomicInteger,以保证它将是高效和有用的。所以作为一个小的弊病,我们在此使用了hotspot原生内置的函数API。在我们处理它的同时,对其他可以cas操作的字段执行了相同的操作。
stateOffset表示类文件中state字段的位置,其他同。
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;
static {
try {
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
}
对队列头、队列尾、队列同步状态进行原子操作:
/**
* CAS head field. Used only by enq.
*/
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
/**
* CAS tail field. Used only by enq.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
/**
* CAS waitStatus field of a node.
*/
private static final boolean compareAndSetWaitStatus(Node node,
int expect,
int update) {
return unsafe.compareAndSwapInt(node, waitStatusOffset,
expect, update);
}
/**
* CAS next field of a node.
*/
private static final boolean compareAndSetNext(Node node,
Node expect,
Node update) {
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
AQS内置属性
/**
* 等待队列头部, 懒加载. 除初始化外,它仅通过方法setHead进行修改。 Note:
*如果head存在,则保证其waitStatus不是CANCELLED。
*/
private transient volatile Node head;
/**
*等待队列的尾部,懒加载。 仅通过方法enq修改以添加新的等待节点。
*/
private transient volatile Node tail;
/**
*同步状态。
*/
private volatile int state;
有此,我们可以得出AQS队列的基本结构:
资源的同步状态-state
AQS中state值在AQS中并没有任何具体的操作,它表示的是线程占有的共享资源值是多少,在我们进行锁的获取操作时,我们可以根据当前的资源值判断我们是否成功获取到了锁(这个在可重入锁和读写锁中都有体现)。子类以通过tryAcquire和tryRelease方法获取和释放资源值,具体的操作根据子类的实现形式决定。
举例来说,在AQS处于独占模式时,
共享资源值=资源值+线程获取资源值;
共享资源值=资源值-线程释放资源值;
资源值为0表示当前没有线程占用资源。
//返回当前同步状态的值
protected final int getState() {
return state;
}
//设置当前同步状态的值,此操作具有易失性写入(volatile)的内存语义。
protected final void setState(int newState) {
state = newState;
}
//原子操作
//若果当前值等于预期值则更新同步状态
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
/**
* 设置自旋时间.
*/
static final long spinForTimeoutThreshold = 1000L;
操作等待队列的基本方法
将等待线程放入到等待队列中。
/**
* 插入节点到队列中
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;//获取尾节点
if (t == null) { // 若尾节点为空,设置头节点并将尾节点为头节点
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;//否则插入结点的前导结点设为尾节点
if (compareAndSetTail(t, node)) {//设置前导的尾节点
t.next = node;
return t;
}
}
}
}
//为当前线程和给定模式创建并排队节点。
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;//前导结点为尾节点
if (pred != null) {//尾节点不为空
node.prev = pred;
if (compareAndSetTail(pred, node)) {//设置前导的尾节点
pred.next = node;
return node;
}
}
enq(node);//尾节点为空,先创建队列在插入
return node;
}
将结点设置为头节点,以进行出队列操作。
/**
* 将结点设为队列头,从而方便出队列操作。仅通过获取方法调用。同时为了GC而将未使用的字段设为空,并抑制不必要的信号和遍历。
*
* @param node the node
*/
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
独占模式下释放结点
/**
*唤醒并断开node节点的后继结点(如果存在)。
*/
private void unparkSuccessor(Node node) {
/*
*如果状态为负(即,可能需要信号),则尝试清除预期信令。 如果失败或者等待线程改变了状态,则可以 */
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
*等待的线程在后继结点中保存,通常只是下一个节点。 但是如果结点取消或显然为空,则从尾部向后移动以找到实际未取消的继任者。
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
共享模式下释放结点
/**
*共享模式的释放操作 - 发出后继节点并确保传播。(注意:对于独占模式,如果需要唤醒,释放只是调用未等待的继承者。)
*/
private void doReleaseShared() {
/*
* 即使存在其他正在进行的获取/释放,也要确保发布传播。 如果它需要信号,这通常会尝试取消停止头部的接入者。 但如果没有,则将状态设置为PROPAGATE以确保在发布时继续传播。此外,我们必须循环以防在添加新节点时执行此操作。 此外,与unparkSuccessor的其他用法不同,我们需要知道CAS重置状态是否失败,如果是这样,则重新检查.
*/
for (;;) {//忙等待
Node h = head;
if (h != null && h != tail) {//头节点不为空,且不为尾节点
int ws = h.waitStatus;//获取头节点的状态
if (ws == Node.SIGNAL) {//若头结点为释放状态
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; //头节点为释放状态则跳过判断下一个
unparkSuccessor(h);//唤醒头节点的后继节点
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; //若头结点为传播状态则跳过判断下一个
}
if (h == head) // 如果头节点改变则循环
break;
}
}
共享模式下根据结点传播状态设置头节点。
/**
* 设置队列头,并检查后继者是否可能在共享模式下等待,如果是传播,则设置传播> 0或PROPAGATE状态。
*/
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // 记录旧的头节点
setHead(node);//将当前结点设为头节点
/*
*尝试唤醒队列中的结点:传播状态由调用者指明,或者通过前一个操作记录可以确定。
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;//查找后继结点
if (s == null || s.isShared())
doReleaseShared();//释放结点
}
}
取消结点
/**
*取消正在进行的尝试获取的node结点。
*/
private void cancelAcquire(Node node) {
//如果节点不存在则忽略
if (node == null)
return;
node.thread = null;//结点线程设为空
// Skip cancelled predecessors
Node pred = node.prev;
while (pred.waitStatus > 0)//若前导结点被取消,则跳过获取前一个
node.prev = pred = pred.prev;
Node predNext = pred.next;
//将结点状态设为取消
node.waitStatus = Node.CANCELLED;
// 若node为尾部,移除自身
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
//如果后继者需要信号,请尝试设置pred的下一个链接,以便获得一个。 否则将其唤醒以进行传播。
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node;
}
}
获取失败后是否停顿,如果等待线程应该释放,则表示应该停顿返回true;如果等待线程被取消,则表示不应该停顿查找有效的前导结点 后返回false
/**
检查并更新无法获取的节点的状态。如果线程应阻止,则返回true。 这是所有采集循环中的主要信号控制。 需要pred == node.prev。
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*此节点已设置状态,并要求释放,以便它可以安全地停放。
*/
return true;
if (ws > 0) {
/*
* 前导结点已被取消. 跳过前导结点并重新查找有效前导结点
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus必须为0或PROPAGATE。表示我们需要一个信号,但是还不能别停顿。调用者需要重试以确保在停顿前无法被获取
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
中断方法以及检查线程停顿的方法
/**
* 中断当前线程的便捷方法
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
* 停顿的便捷方法并检查是否中断
*/
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
判断队列的模式、获取队列头结点中的等待线程、以及判断等待线程是否在等待队列中:
/**
*当fastpath失败时调用getFirstQueuedThread的版本
*/
private Thread fullGetFirstQueuedThread() {
/*
*第一个节点通常是head.next。 尝试获取其线程字段,确保一致性读取:如果线程字段被清空或s.prev不再是head,那么一些其他线程在我们的一些读取之间同时执行setHead。 我们在尝试遍历之前尝试了两次。
*/
Node h, s;
Thread st;
if (((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null) ||
((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null))
return st;
/*
* Head的下一个字段可能尚未设置,或者可能在setHead之后未设置。 所以我们必须检查尾部是否真的是第一个节点。 如果没有,我们继续,安全地从尾部回到头部找到第一个,保证终止。
*/
Node t = tail;
Thread firstThread = null;
while (t != null && t != head) {
Thread tt = t.thread;
if (tt != null)
firstThread = tt;
t = t.prev;
}
return firstThread;
}
/**
*如果给定线程当前已排队,则返回true。
*/
public final boolean isQueued(Thread thread) {
if (thread == null)
throw new NullPointerException();
for (Node p = tail; p != null; p = p.prev)
if (p.thread == thread)
return true;
return false;
}
/**
*如果第一个排队的线程(如果存在)在独占模式下等待,则返回true。 如果此方法返回true,并且如果当前线程正在尝试以共享模式获取(即,此方法是从tryAcquireShared调用的),那么可以保证当前读取的不是第一个排队线程。 仅用作ReentrantReadWriteLock中的启发式。
*/
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
获取资源的方式
各种风格的获取,在独占/共享和控制模式中有所不同。每个都大致相同,但有些不同。由于异常机制的交互(包括确保我们取消,如果tryAcquire抛出异常)和其他控制,只有一点因素可能是可能的,至少在不损害性能太多的情况下。
相同的是,在使某一结点获取资源时,若该资源的前导资源不为头节点即还有其他等待线程,则该节点获取资源的操作就处于忙循环,在未成功之前会一直进行循环等待直到该节点的等待线程获取到资源。
不同的是该节点线程是否中断,是否停顿等条件不同。
/**
*对于已经在队列中的线程,以独占不间断模式获取。由条件等待方法使用以及获取。
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;//不可中断
for (;;) {//死循环
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; //将后继结点设为空便于GC
failed = false;//获取资源成功
return interrupted;//返回false
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())//线程中断
interrupted = true;
}
} finally {
if (failed)//若获取资源失败
cancelAcquire(node);//取消node结点
}
}
/**
*以独占可中断模式获取。
*/
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;//不返回线程状态
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())//停顿检测中断
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
*以独占定时模式获取.
*/
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);//停顿一定时间
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
*以共享不间断模式获取。
*/
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
*以共享可中断模式获取。
*/
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
*以共享定时模式获取。
*/
private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return true;
}
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
条件(Condition)队列到等待队列的转换
这些方法将负责把条件队列中的结点转移到等待队列中,转移时也先判断当前结点是否在等队列中。主要完成了条件队列与等待队列之间的转换。
/**
*如果节点(始终是最初放置在条件队列中的节点)现在正在等待重新获取同步队列,则返回true。
*/
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
if (node.next != null) // 如果有后继节点,则一定在队列中
return true;
/*
* node.prev可以是非空的,但尚未在队列中,因为将其置于队列中的CAS可能会失败。 所以我们必须从
*尾部遍历以确保它真正成功。 在调用此方法时,它总是接近尾部,除非CAS失败(这不太可能),它将
*存在,所以我们几乎不会遍历很多。
*/
return findNodeFromTail(node);
}
/**
*如果节点通过从尾部向前搜索处于同步队列中,则返回true。仅在isOnSyncQueue需要时才调用。
* @return true if present
*/
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
/**
*将节点从条件队列传输到同步队列。如果成功则返回true。
*/
final boolean transferForSignal(Node node) {
/*
*若等待状态不能改变,则结点处于已经被取消
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
*拼接到队列并尝试设置前导结点的waitStatus以指明该线程(可能)正在等待。 如果取消或尝试设置
*waitStatus失败,则唤醒重新同步(在这种情况下,waitStatus可能是暂时且无害的)。
*/
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
/**
*如果需要,在取消等待后将节点转移到同步队列。如果线程在发出信号之前被取消,则返回true。
*
* @param node the node
* @return true if cancelled before the node was signalled
*/
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
/*
*如果我们丢失了一个信号量,那么我们就不能继续它直到完成它的插入。 在不完全转移期间取消既罕见
*又短暂,所以只需旋转。
*/
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
/**
*使用当前状态值释放node; 返回保存状态。取消节点并在失败时抛出异常.
* @param node the condition node for this wait
* @return previous sync state
*/
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
条件队列的操作-ConditionObject
AbstractQueuedSynchronizer 的 Condition 实现是 Lock 实现的基础。
此类的方法文档描述了一些机制,但没有从 Lock 和 Condition 用户的角度描述行为规范。此类的发行版本通常必须和描述 condition 语义的文档一起提供,这些语义依赖于相关 AbstractQueuedSynchronizer 的那些语义。
此类是可序列化的,但所有字段都是瞬态的,所以已序列化的条件没有等待者。
该类负责条件队列中等待线程的添加和释放。
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
/** 条件队列的第一个结点 */
private transient Node firstWaiter;
/** 条件队列的最后一个结点 */
private transient Node lastWaiter;
/**
*创建一个条件对象实例
*/
public ConditionObject() { }
// Internal methods
/**
* 添加一个等待者到队列
*/
private Node addConditionWaiter() {
Node t = lastWaiter;
// 若最后的结点被取消,则清除结点.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();//断开想取消的结点
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)//尾结点为空
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
/**
*删除并传输节点,直到命中未取消的节点或null。 从信号拆分出来的部分,以鼓励编译器内联没有等待的情况。
* @param first (non-null) the first node on condition queue
*/
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
/**
* 删除并传输所有结点
* @param first (non-null) the first node on condition queue
*/
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
/**
*从条件队列断开已取消的等待节点。 仅在锁定时调用。在条件等待期间发生取消时以及在看到
*lastWaiter被取消时插入新等待者时调用此方法。需要此方法以避免在没有信号的情况下留下垃圾。
*因此,即使它可能需要完全遍历,但只有在没有信号的情况下发生超时或取消时才会发挥作用。
*它遍历所有节点而不是停留在特定目标,以取消所有指向垃圾节点的指针,而不需要在取消结点期间进
*行多次重新遍历。
*/
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {//首节点不为空
Node next = t.nextWaiter;//查找下一个结点
if (t.waitStatus != Node.CONDITION) {//若等待状态被取消
t.nextWaiter = null;//该节点的指针为空
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;//未被取消则保存该节点
t = next;
}
}
// public methods
/**
*将等待时间最长的线程(如果存在)从此条件的等待队列中移动到拥有锁的等待队列。
*
*/
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
/**
*将所有线程从此条件的等待队列移动到拥有锁的等待队列中。
*/
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
/**
*实现不可中断的条件等待
*/
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
/*
*对于可中断的等待,我们需要跟踪是否抛出InterruptedException,
*如果在条件被阻塞时被中断,则重新中断当前线程,如果在被阻塞等待重新获取时被中断则抛出异常。
*/
/**模式意味着在退出等待时重新中断*/
private static final int REINTERRUPT = 1;
/**模式意味着在退出等待时抛出InterruptedException */
private static final int THROW_IE = -1;
/**
*检查中断,如果在发出信号之前中断则返回THROW_IE,如果发出信号则返回REINTERRUPT,如果没有中断则返回0。
*/
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
/**
*抛出InterruptedException,重新中断当前线程,或者什么都不做,具体取决于模式。
*/
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
/**
*实现不可中断的条件等待。
*/
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/**
*实现定时的条件等待。
*/
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
/**
*实现绝对定时条件等待。
*/
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
/**
* 等待
*/
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
timedout = transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
/**
*如果此条件是由给定的同步对象创建的,则返回true。
*/
final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
return sync == AbstractQueuedSynchronizer.this;
}
/**
* 返回条件队列中的等待结点数量
*/
protected final boolean hasWaiters() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
return true;
}
return false;
}
/**
*返回正在等待此条件的线程数估计值。
* 实现了AbstractQueuedSynchronizer的getWaitQueueLength(ConditionObject)方法.
*/
protected final int getWaitQueueLength() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int n = 0;
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
++n;
}
return n;
}
/**
*返回包含那些可能正在等待此条件的线程集合。
*实现了AbstractQueuedSynchronizer的getWaitingThreads(ConditionObject)方法.
*
*/
protected final Collection<Thread> getWaitingThreads() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION) {
Thread t = w.thread;
if (t != null)
list.add(t);
}
}
return list;
}
}