目录
- 一、前言
- 二、带着问题看源码
- 三、public方法
- 四、独占模式源码分析
- 4.1 acquire 可以被外部类调用的public方法
- 4.2 tryAcquire 需要被子类重写(这里以ReentrantLock为例)
- 4.3 addWaiter 将当前线程包装成节点并入队
- 4.4 enq 初始化头结点并将当前节点入队
- 4.5 acquireQueued 线程在当前方法循环阻塞、唤醒、尝试获取资源、失败阻塞,成功退出的过程
- 4.6 setHead 设置头结点,头结点占有线程
- 4.7 shouldParkAfterFailedAcquire 判断获取资源失败后是否应该获取资源。主要工作:修改前驱节点的状态为SIGNAL,清除队列中被取消的节点(waitStatus为CANCELLED)
- 4.8 parkAndCheckInterrupt 阻塞当前线程,当其唤醒后,会返回当前线程是否被中断,并清除中断标记位
- 4.9 cancelAcquire 当前节点设为CANCELLED,并移除同步等待队列
- 4.10 selfInterrupt 当前线程设置中断标记
- 4.11 unparkSuccessor 唤醒后继者
- 4.12 tryAcquireNanos 尝试指定时间内能否获取锁。可以被外部类调用的public方法
- 4.13 doAcquireNanos 获取锁,等待指定时间,超时被唤醒再次尝试获取资源失败后返回false
- 4.1.4 acquireInterruptibly 可中断地获取资源。可以被外部类调用的public方法
- 4.15 doAcquireInterruptibly 可中断地获取资源。
- 4.16 release 释放资源/释放锁。可以被外部类调用的public方法
- 4.17 tryRelease 需要被子类重写。尝试释放资源(这里以ReentrantLock为例)
- 4.18 hasQueuedPredecessors() 判断队列里是否还有节点,进而决定公平锁情况下能够直接获取锁。
- 五、共享模式源码分析
- 六、整体源码注释
一、前言
AQS逻辑分为三部分:独占模式(锁标识为EXCLUSIVE)、共享模式(锁标识为SHARED)、条件队列(也就是内部类ConditionObject里的逻辑)。
其中,条件队列依附于独占模式(只有独占模式情况下才会用到ConditionObject)。本文主要讲独占模式及共享模式下涉及到的源码。
共享模式和独占模式在state资源数上赋予的意义不同,共享模式的state类似于许可数,值为0时则无法再获取锁。而独占模式的state类似于某线程占用该锁的次数,次数为0时才可以获取锁。
本文适合在理解Node内部类、CAS后阅读
二、带着问题看源码
2.1 源码里独占模式和共享模式字段对应的值是什么,这样设计带来的影响是什么
2.2 Node.waitStatus在AQS中有哪些状态,代表意义,设置或变更时机是什么
2.3 acquire/acquireInterruptibly/tryAcquireNanos三者的区别是什么
三、public方法
3.1 独占模式
独占模式有四个公共方法:
获取资源:acquire,acquireInterruptibly,tryAcquireNanos
释放资源:release
3.1.1 简略流程图
3.1.1.1 acquire方法
3.1.1.2 acquireInterruptibly方法
3.1.1.3 tryAcquireNanos方法
3.1.1.4 release方法
3.1.2 方法列表
- acquire
- tryAcquire
- addWaiter
- enq
- acquireQueued
- setHead
- shouldParkAfterFailedAcquire
- parkAndCheckInterrupt
- cancelAcquire
- unparkSuccessor
- LockSupport.unpark
- tryAcquireNanos
- doAcquireNanos
- acquireInterruptibly
- doAcquireInterruptibly
- release
- tryRelease
3.1.3 详细流程
3.1.4 线程被阻塞的流程
3.1.5 线程释放流程
3.2 共享模式
共享模式同样有四个公共方法:
获取资源:acquireShared,acquireSharedInterruptibly,tryAcquireSharedNanos
释放资源:releaseShared
共享模式下的四个公共方法基本逻辑与独占模式相同,最主要的不同点在于获取到资源时的处理不同setHeadAndPropagate
3.2.1 简略流程图
3.2.1.1 acquireShared
3.2.1.2 releaseShared
3.2.2 共享模式用到,独占模式没用到的方法列表
- acquireShared
- tryAcquireShared
- doAcquireShared
- setHeadAndPropagate
- doReleaseShared
- doAcquireSharedInterruptibly
- doAcquireSharedNanos
3.3 条件队列入队出队简图
简述一下流程。
有线程0、1、2 、3 和主线程
第一张图:主线程持有锁,四个线程尝试获取锁,获取失败进入同步队列
第二张图:主线程释放锁,头的后继结点线程0被唤醒获取到锁,调用await方法,释放锁并进入条件队列。此时线程1处于头的后继结点。
第三张图:线程1被唤醒,获取到锁,调用await方法,释放锁进入条件队列队尾,并让主线程获取到锁
第四张图:主线程调用signal方法,唤醒条件队列队首线程0,线程0直接尝试获取锁,获取失败进入同步队列队尾
条件队列特点:
先进先出
与同步队列不同,无空头结点
四、独占模式源码分析
4.1 acquire 可以被外部类调用的public方法
/**
* 尝试获取arg个资源数,如果失败,就包装成独占锁的节点进入队列。
* 如果进入队列后直接能获取到资源,则结束
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
4.2 tryAcquire 需要被子类重写(这里以ReentrantLock为例)
用于被子类重写,判断当前能否直接获取到锁。
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
以ReentrantLock重写的非公平方法为例。先获取当前占用资源数,判断如果是0,或者当前线程已经获取过了,则获取成功,否则获取锁失败,返回false。
/**
* 尝试以非公平方式获取资源
*/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
/**
* 非公平尝试获取锁
* 当发现资源未上锁,cas尝试获取
* 否则判断是否已拥有,重入锁。
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
4.3 addWaiter 将当前线程包装成节点并入队
/**
* 1.将当前节点封装成对应模式的节点
* 2.cas将当前节点设置成尾节点
* @param mode 节点模式,这里传的独占模式Node.EXCLUSIVE
* @return 包装后的节点
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 如果队列中尾指针不为空,尝试将当前节点放到尾节点上,并且cas尝试将尾指针指向当前节点
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 不断尝试入队
enq(node);
return node;
}
可以看到,Node构造函数传了两个参数:当前线程和mode模式。
mode模式有两种:
- 共享锁标识 static final Node SHARED = new Node();
- 独占锁标识 static final Node EXCLUSIVE = null;
nextWaiter被赋值为mode,说明如果使用了等待队列,那么当前模式一定是独占模式的(独占模式下nextWaiter才可以被赋值,共享模式不可以被赋值,赋值后无法判断是否为共享模式)
/**
* 构造
*/
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
4.4 enq 初始化头结点并将当前节点入队
/**
* 如果队列为空,就建头结点
* 尝试将当前节点入队
* @param node 当前节点
* @return 原先的尾节点
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// 如果尾节点为null,说明队列为空,需要新建头结点,然后下次循环将当前节点加进去
if (t == null) {
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 有头结点则cas设置尾节点
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
4.5 acquireQueued 线程在当前方法循环阻塞、唤醒、尝试获取资源、失败阻塞,成功退出的过程
/**
* 将同步队列中的节点阻塞,被唤醒后则再次尝试获取资源,失败再阻塞,处于循环中
* 直到抛出异常或者线程获取到了资源
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取前序节点,如果前序节点是头,并且当前线程能够获取到资源,则将当前节点变为头,并且使之前的头脱离队列
final Node p = node.predecessor();
// 如果p是头结点(说明node是队列中除了头的唯一节点)并且尝试获取资源成功
if (p == head && tryAcquire(arg)) {
// 设置当前节点为头结点,并且将原来的头移除队列
setHead(node);
// 原来头的后继指向null
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果前序节点不是头,或者获取资源失败,
// 正常来讲,shouldParkAfterFailedAcquire这里node为队尾,p为node的前驱节点。
// 如果p的waitStatus为0,设为SIGNAL,返回false进入下轮循环。
// 如果为SIGNAL返回true进入parkAndCheckInterrupt
if (shouldParkAfterFailedAcquire(p, node) &&
// 在这里阻塞,被唤醒后返回当前线程中断状态并清除中断标记。如果被中断过返回true,进入if方法内部
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// try抛异常则取消获取资源
if (failed)
cancelAcquire(node);
}
}
4.6 setHead 设置头结点,头结点占有线程
/**
* 设置某节点为头结点
* @param node 一般是队首节点(默认头结点除外)
*/
private void setHead(Node node) {
head = node;
// 头结点不占有线程
node.thread = null;
node.prev = null;
}
4.7 shouldParkAfterFailedAcquire 判断获取资源失败后是否应该获取资源。主要工作:修改前驱节点的状态为SIGNAL,清除队列中被取消的节点(waitStatus为CANCELLED)
/**
* 判断获取资源失败后是否应该获取资源。主要工作:修改前驱节点的状态为SIGNAL,清除队列中被取消的节点(waitStatus为CANCELLED)
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
// 如果前序节点的waitStatus状态为SIGNAL,说明当前节点等待被唤醒,可以park阻塞
if (ws == Node.SIGNAL)
return true;
// 如果是CANCELLED状态,从前序节点往前找,将所有CANCELLED状态的节点移除队列
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 如果是0、-3、-2,比较并设置前驱节点的状态为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
// 不进行park阻塞操作
return false;
}
4.8 parkAndCheckInterrupt 阻塞当前线程,当其唤醒后,会返回当前线程是否被中断,并清除中断标记位
关于LockSupport可以看这篇文章 LockSupport源码理解
/**
* 阻塞当前线程,当其唤醒后,会返回当前线程是否被中断,并清除中断标记位
*/
private final boolean parkAndCheckInterrupt() {
// 线程中断或者被unpark都可以被唤醒
LockSupport.park(this);
return Thread.interrupted();
}
Thread.interrupted() 方法会返回中断标记和清除中断标记。true为已中断
4.9 cancelAcquire 当前节点设为CANCELLED,并移除同步等待队列
一个比较令人费解的方法。unparkSuccessor的时机我不太理解。
/**
* 将节点移除同步队列,设置当前节点状态为CANCELLED
* 从当前位置向前找,把遇到的CANCELLED节点都移除,直到不是CANCELLED的节点
* 如果一直找到头结点,有机会唤醒node的后继节点
*/
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
// 取到此节点之前最近的状态小于0的节点
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 循环执行结束后,node.prev的waitStatus<=0
// 记录pred的下一个节点,用于cas设置pred的next
Node predNext = pred.next;
// 设置当前节点状态为CANCELLED
node.waitStatus = Node.CANCELLED;
// 如果这个节点已经是尾节点,就把尾节点设置为pred(非CANCELLED的节点)
if (node == tail && compareAndSetTail(node, pred)) {
// cas设置pred的next为null
compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
// 如果node已经不是尾节点了
int ws;
// 防止pred为头结点,并且pred的等待状态为SIGNAL时才能往下走
// 如果pred不是头结点 并且 (pred.waitStatus为SIGNAL 或 pred.waitStatus<=0且cas设置为SIGNAL成功) 并且 pred.thread不为null
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
// 进到这里说明node后面被加了节点。所以要将pred的后继指向node的后继
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
// node != tail && ( pred == head || pred.thread == null || pred.waitStatus!=Node.SIGNAL && (pred.waitStatus>0|| casFailed))
// pred为头结点,或者 pred被取消了 或者 cas设置pred的状态为SIGNAL失败了?才去唤醒node的后继节点
unparkSuccessor(node);
}
// 为什么这样会help GC呢
node.next = node; // help GC
}
}
4.10 selfInterrupt 当前线程设置中断标记
/**
* 当前线程设置中断标记
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
4.11 unparkSuccessor 唤醒后继者
我一直理解唤醒的都是头结点的后继者。但是该方法是唤醒了入参的后继,我还没有找到传参为头之外的情况。
/**
* 唤醒该节点的后继节点
* @param node 一般是head节点
*/
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
// 如果状态小于0,为SIGNAL -1 或 CONDITION -2 或 PROPAGATE -3,将其设置为0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
// 下一个结点为空或者下一个节点的等待状态大于0,即为CANCELLED
if (s == null || s.waitStatus > 0) {
s = null;
// 从尾结点开始从后往前开始遍历
for (Node t = tail; t != null && t != node; t = t.prev)
// 找到等待状态小于等于0的结点,找到最前的状态小于等于0的结点, 保存结点
if (t.waitStatus <= 0)
s = t;
}
// 该结点不为为空,释放许可,在这里阻塞的线程被唤醒
if (s != null)
LockSupport.unpark(s.thread);
}
4.12 tryAcquireNanos 尝试指定时间内能否获取锁。可以被外部类调用的public方法
/**
* 尝试指定时间内能否获取锁。
* @param arg 资源数
* @param nanosTimeout 相对等待时间
* @return 是否获取成功
* @throws InterruptedException 中断异常
*/
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 先尝试获取资源是否成功,失败的话尝试指定时间内是否能获取锁成功
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
4.13 doAcquireNanos 获取锁,等待指定时间,超时被唤醒再次尝试获取资源失败后返回false
和requireQueued的区别:
- 唤醒方式不同:
- requireQueued: 被其它线程LockSupport.unpark、被中断才会被唤醒
- doAcquireNanos: 被其它线程LockSupport.unpark、被中断、超时会被唤醒
- 退出循环方式不同:
- requireQueued: 被唤醒后,在循环中通过判断当前节点是否为头的后继节点和是否能获取资源来退出循环
- doAcquireNanos: 被唤醒后,在循环中判断完是否获取资源后,还会判断是否超时来退出循环
- 中断处理不同:
- requireQueued: 不处理中断,只返回中断信息
- doAcquireNanos: 中断后抛出异常
/***
* 尝试指定时间内能否获取锁。
* 实际退出方法时间一定比nanosTimeout时间长
* @param arg 请求资源数量
* @param nanosTimeout 相对等待时间
* @return 是否获取成功
* @throws InterruptedException 异常
*/
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();
// 如果超时了,直接返回false
if (nanosTimeout <= 0L)
return false;
// 判断是否需要阻塞,
// 如果等待时间比自旋时间小,则用for循环等待获取锁。
// 否则用LockSupport阻塞对应时间,被唤醒后在下一轮循环判断能否获取锁并退出
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
// 可以响应中断,抛出异常
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
4.1.4 acquireInterruptibly 可中断地获取资源。可以被外部类调用的public方法
/**
* 可中断地获取资源
* acquire和acquireInterruptibly两者区别是:
* acquire不响应中断,只标记中断位
* doAcquireInterruptibly遇到中断则抛出异常
*/
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
4.15 doAcquireInterruptibly 可中断地获取资源。
和acquireQueued基本完全相同,只是对中断的处理不同。
/**
* 想想这个方法和acquireQueued有什么区别?
* 这个方法无返回值。中断直接抛异常
* acquireQueued返回是否中断,并且交给selfInterrupt标记中断
* 所以两者区别是:
* acquire不响应中断,只标记中断位
* doAcquireInterruptibly遇到中断则抛出异常
*/
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);
}
}
4.16 release 释放资源/释放锁。可以被外部类调用的public方法
/**
* 释放资源,如果全部释放,唤醒同步队列头结点之后的节点(不再阻塞)
*/
public final boolean release(int arg) {
// 如果尝试释放资源成功(释放资源,如果全部释放,资源不再被锁住)
if (tryRelease(arg)) {
Node h = head;
// 如果头节点不为空且头的waitStatus不为0,释放后继者
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
4.17 tryRelease 需要被子类重写。尝试释放资源(这里以ReentrantLock为例)
/**
* 完全释放锁后,state为0,设置独占线程为空
* @param releases 释放数量
* @return 是否成功
*/
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
4.18 hasQueuedPredecessors() 判断队列里是否还有节点,进而决定公平锁情况下能够直接获取锁。
- h != t && h.next == null 这种情况发生在enq,刚刚将头结点指向新建的头结点,但是尾节点还未赋值为头结点。这种情况说明已经有线程获取到了锁,并且有线程被阻塞,公平模式下的线程需要进入队列。
- h != t && s.thread != Thread.currentThread() 说下h!=t&&s.thread!=Thread.currentThread()的情况。这种情况发生在当前线程已经进入了同步队列等待,并且是头的后继节点。刚刚占有锁的线程释放了锁,于此同时当前线程再次尝试获取锁,因此这时就不需要再进入队列了。
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return h != t && // 头不等尾,说明除了头结点还有其他节点
((s = h.next) == null // 头不等于尾 并且 h.next == null,说明此时处于enq,刚将头指向新建节点
|| s.thread != Thread.currentThread()); // 头不等于尾 并且 头的后继不是当前线程。 如果是当前线程,说明当前线程被release的unpark唤醒后,还未出队就又尝试获取锁,这时公平锁情况允许直接获取锁
}
五、共享模式源码分析
5.1 setHeadAndPropagate 设置头结点并向后唤醒传播
六、整体源码注释
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import sun.misc.Unsafe;
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
/**
* 序列化id
*/
private static final long serialVersionUID = 7373984972572414691L;
/**
* 空构造
*/
protected AbstractQueuedSynchronizer() { }
/**
* 队列里的节点
*/
static final class Node {
/**
* 共享锁标识
*/
static final Node SHARED = new Node();
/**
* 排它锁标识
*/
static final Node EXCLUSIVE = null;
/**
* 取消状态
*/
static final int CANCELLED = 1;
/**
* 将后续节点unparking,唤醒
*/
static final int SIGNAL = -1;
/**
* 将等待队列里的线程唤醒
*/
static final int CONDITION = -2;
/**
* waitStatus 值指示下一个 acquireShared 应该无条件传播
*/
static final int PROPAGATE = -3;
/**
* 等待状态,从上面四个里取,或者为0,为0代表在同步对垒里
*/
volatile int waitStatus;
/**
* 同步队列的前指针
*/
volatile Node prev;
/**
* 同步队列的后继指针
*/
volatile Node next;
/**
* 包装的线程对象
*/
volatile Thread thread;
/**
* 链接到等待条件的下一个节点,或特殊值 SHARED。
* 因为条件队列只有在独占模式下才会被访问,
* 所以我们只需要一个简单的链接队列来在节点等待条件时保持节点。
* 然后将它们转移到队列中以重新获取。
* 并且因为条件只能是独占的,
* 所以我们使用特殊值来保存一个字段来表示共享模式。
*/
Node nextWaiter;
/**
* 构造
*/
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;
}
/**
* 判断当前是否为共享模式
* <div></div>
* 看起来是通过nextWaiter设置成SHARED的方式来定共享
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 同步队列中的前序节点
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
}
/**
* 同步队列的头
* 唤醒节点时,需要从头结点的后继节点开始。
* 需要头的waitStatus为SIGNAL(还是说小于0就行)
* 唤醒后继后,将原来的头的waitStatus设为0,并移除队列?为什么要设为0
* 后继设为头,
*/
private transient volatile Node head;
/**
* 同步队列尾节点,延迟初始化,只能通过enq方法添加新等待节点
*/
private transient volatile Node tail;
/**
* 同步资源数
*/
private volatile int state;
/**
* 获取状态
*/
protected final int getState() {
return state;
}
/**
* 设置资源数
*
* 这里不需要cas,我理解是获取锁后才会调用该方法,不会发生多线程修改的情况
*/
protected final void setState(int newState) {
state = newState;
}
/**
* cas设置状态
*/
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
/**
* 自旋时间,纳秒
*/
static final long spinForTimeoutThreshold = 1000L;
/**
* 如果队列为空,就建头结点
* 尝试将当前节点入队
* @param node 当前节点
* @return 原先的尾节点
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// 如果尾节点为null,说明队列为空,需要新建头结点,然后继续将当前节点加进去
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 有头结点则cas设置尾节点
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
/**
* 1.将当前节点封装成对应模式的节点
* 2.cas将当前节点设置成尾节点
* @param mode 独占模式
* @return 包装后的节点
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 如果队列中尾指针不为空,尝试将当前节点放到尾节点上,并且cas尝试将尾指针指向当前节点
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 不断尝试入队
enq(node);
return node;
}
/**
* 设置某节点为头结点
* @param node 一般是队首节点(默认头结点除外)
*/
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
/**
* 唤醒该节点的后继节点
* @param node 一般是head节点
*/
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
// 如果状态小于0,为SIGNAL -1 或 CONDITION -2 或 PROPAGATE -3,将其设置为0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
// 下一个结点为空或者下一个节点的等待状态大于0,即为CANCELLED
if (s == null || s.waitStatus > 0) {
s = null;
// 从尾结点开始从后往前开始遍历
for (Node t = tail; t != null && t != node; t = t.prev)
// 找到等待状态小于等于0的结点,找到最前的状态小于等于0的结点, 保存结点
if (t.waitStatus <= 0)
s = t;
}
// 该结点不为为空,释放许可
if (s != null)
LockSupport.unpark(s.thread);
}
/**
* 共享模式的释放,从头结点的后继开始传播
*/
private void doReleaseShared() {
/*
* 即使有其他正在进行的获取/释放,也要保证释放传播。
* 通常情况下,一个程序如果需要唤醒,就要试图唤醒头结点的后继者。
* 但在这里不是这样的,节点状态被设置成传播来确保释放后传播还在继续
* 另外,当我们在释放时候,我们必须循环万一一个新节点正在添加
* 同样,不像其它唤醒后继的方式,我们需要知道是否CAS重设状态失败,如果是则重新检察
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
// 唤醒后继者前,需要先将头的waitStatus从SINGAL变成0,然后再去唤醒后继者
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
/**
* 设置队列的头结点,检查是否为共享模式等条件,释放队列中的节点
* @param node 一般是后的后继节点
* @param propagate tryAcquireShared的返回值
*/
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
// 设置当前节点为头结点,thread和前驱为null
setHead(node);
/*
* 尝试在以下情况下发出下一个排队节点的信号:
* 传播由调用者指示,或者被先前的操作记录(作为 setHead 之前或之后的 h.waitStatus)
* (注意:这使用了 waitStatus 的符号检查,因为传播状态可能会转换为 SIGNAL。 )
* 和下一个节点在共享模式下等待,或者我们不知道,
* 因为它出现了 null 这两个检查中的保守性可能会导致不必要的唤醒,
* 但只有当有多个竞速获取/释放时,
* 所以最需要 无论如何,现在或很快就会发出信号。
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
// 如果当前节点的下个节点为null 或者 当前节点是共享模式的
if (s == null || s.isShared())
// 释放同步队列中的节点
doReleaseShared();
}
}
/**
* 取消获取资源,设置当前节点状态为CANCELLED
*/
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
// 取到此节点之前最近的状态小于0的节点
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 循环执行结束后,node.prev的waitStatus<=0
// 记录pred的下一个节点,用于cas设置pred的next
Node predNext = pred.next;
// 设置当前节点状态为CANCELLED
node.waitStatus = Node.CANCELLED;
// 如果这个节点已经是尾节点,就把尾节点设置为pred(非CANCELLED的节点)
if (node == tail && compareAndSetTail(node, pred)) {
// cas设置pred的next为null
compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
// 如果node已经不是尾节点了
int ws;
// 防止pred为头结点,并且pred的等待状态为SIGNAL时才能往下走
// 如果pred不是头结点 并且 (pred.waitStatus为SIGNAL 或 pred.waitStatus<=0且cas设置为SIGNAL成功) 并且 pred.thread不为null
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
// 进到这里说明node后面被加了节点。所以要将pred的后继指向node的后继
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
// node != tail && ( pred == head || pred.thread == null || pred.waitStatus!=Node.SIGNAL && (pred.waitStatus>0|| casFailed))
// pred为头结点,或者 pred被取消了 或者 cas设置pred的状态为SIGNAL失败了?才去唤醒node的后继节点
unparkSuccessor(node);
}
// 为什么这样会help GC呢
node.next = node; // help GC
}
}
/**
* 判断获取资源失败后是否应该获取资源。主要工作:修改前驱节点的状态为SIGNAL,清除队列中被取消的节点(waitStatus为CANCELLED)
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
// 如果前序节点的waitStatus状态为SIGNAL,说明当前节点等待被唤醒,可以park阻塞
if (ws == Node.SIGNAL)
return true;
// 如果是CANCELLED状态,从前序节点往前找,将所有CANCELLED状态的节点移除队列
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 如果是0、-3、-2,比较并设置前驱节点的状态为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
// 不进行park阻塞操作
return false;
}
/**
* 当前线程设置中断标记
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
* 阻塞当前线程,当其唤醒后,会返回当前线程是否被中断,并清除中断标记位
*/
private final boolean parkAndCheckInterrupt() {
// 线程中断或者被unpark都可以被唤醒
LockSupport.park(this);
return Thread.interrupted();
}
/**
* 将同步队列中的节点阻塞,被唤醒后则再次尝试获取资源,失败再阻塞,处于循环中
* 直到抛出异常或者线程获取到了资源
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取前序节点,如果前序节点是头,并且当前线程能够获取到资源,则将当前节点变为头,并且使之前的头脱离队列
final Node p = node.predecessor();
// 如果p是头结点(说明node是队列中除了头的唯一节点)并且尝试获取资源成功
if (p == head && tryAcquire(arg)) {
// 设置当前节点为头结点
setHead(node);
// 原来头的后继指向null,并且将原来的头移除队列
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果前序节点不是头,或者获取资源失败,
// 正常来讲,shouldParkAfterFailedAcquire这里node为队尾,p为node的前驱节点。
// 如果p的waitStatus为0,设为SIGNAL,返回false进入下轮循环。
// 如果为SIGNAL返回true进入parkAndCheckInterrupt
if (shouldParkAfterFailedAcquire(p, node) &&
// 在这里阻塞,被唤醒后返回当前线程中断状态并清除中断标记。如果被中断过返回true,进入if方法内部
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// try抛异常则取消获取资源
if (failed)
cancelAcquire(node);
}
}
/**
* 想想这个方法和acquireQueued有什么区别?
* 这个方法无返回值。中断直接抛异常
* acquireQueued返回是否中断,并且交给selfInterrupt标记中断
* 所以两者区别是:
* acquire不响应中断,只标记中断位
* doAcquireInterruptibly遇到中断则抛出异常
*/
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);
}
}
/***
* 尝试指定时间内能否获取锁。
* 实际退出方法时间一定比nanosTimeout时间长
* @param arg 请求资源数量
* @param nanosTimeout 相对等待时间
* @return 是否获取成功
* @throws InterruptedException 异常
*/
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();
// 如果超时了,直接返回false
if (nanosTimeout <= 0L)
return false;
// 判断是否需要阻塞,
// 如果等待时间比自旋时间小,则用for循环等待获取锁。
// 否则用LockSupport阻塞对应时间,被唤醒后在下一轮循环判断能否获取锁并退出
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
// 可以响应中断,抛出异常
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
* Acquires in shared uninterruptible mode.
* @param arg the acquire argument
*/
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;
}
}
// 头结点状态为SIGNAL时返回true,否则将头结点设为SIGNAL
if (shouldParkAfterFailedAcquire(p, node) &&
// 阻塞当前线程,返回中断状态
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
* Acquires in shared timed mode.
*
* @param arg the acquire argument
* @param nanosTimeout max wait time
* @return {@code true} if acquired
*/
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);
}
}
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
/**
* 尝试在共享模式下获取资源
* 一般通过判断当前state是否为0来决定是否可以获取资源
* @param arg 资源数量
* @return 成功获取的数量
*/
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
/**
* 需要被重写方法,尝试释放共享资源
*
* 正常的判断方式是 state-arg后是否为0,为0则释放成功,否则失败。
* @param arg 资源数量
* @return 是否释放成功
*/
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
/**
* 尝试获取arg个资源数,如果失败,就包装成独占锁的节点进入队列。
* 如果进入队列后直接能获取到资源,则结束
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
/**
* 可中断地获取资源
* acquire和acquireInterruptibly两者区别是:
* acquire不响应中断,只标记中断位
* doAcquireInterruptibly遇到中断则抛出异常
*/
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
/**
* 尝试指定时间内能否获取锁。
* @param arg 资源数
* @param nanosTimeout 相对等待时间
* @return 是否获取成功
* @throws InterruptedException 中断异常
*/
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 先尝试获取资源是否成功,失败的话尝试指定时间内是否能获取锁成功
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
/**
* 释放资源,如果全部释放,唤醒同步队列头结点之后的节点(不再阻塞)
*/
public final boolean release(int arg) {
// 如果尝试释放资源成功(释放资源,如果全部释放,资源不再被锁住)
if (tryRelease(arg)) {
Node h = head;
// 如果头节点不为空且头的waitStatus不为0,释放后继者
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
/**
* Acquires in shared mode, ignoring interrupts. Implemented by
* first invoking at least once {@link #tryAcquireShared},
* returning on success. Otherwise the thread is queued, possibly
* repeatedly blocking and unblocking, invoking {@link
* #tryAcquireShared} until success.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquireShared} but is otherwise uninterpreted
* and can represent anything you like.
*/
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
/**
* Acquires in shared mode, aborting if interrupted. Implemented
* by first checking interrupt status, then invoking at least once
* {@link #tryAcquireShared}, returning on success. Otherwise the
* thread is queued, possibly repeatedly blocking and unblocking,
* invoking {@link #tryAcquireShared} until success or the thread
* is interrupted.
* @param arg the acquire argument.
* This value is conveyed to {@link #tryAcquireShared} but is
* otherwise uninterpreted and can represent anything
* you like.
* @throws InterruptedException if the current thread is interrupted
*/
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
/**
* Attempts to acquire in shared mode, aborting if interrupted, and
* failing if the given timeout elapses. Implemented by first
* checking interrupt status, then invoking at least once {@link
* #tryAcquireShared}, returning on success. Otherwise, the
* thread is queued, possibly repeatedly blocking and unblocking,
* invoking {@link #tryAcquireShared} until success or the thread
* is interrupted or the timeout elapses.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquireShared} but is otherwise uninterpreted
* and can represent anything you like.
* @param nanosTimeout the maximum number of nanoseconds to wait
* @return {@code true} if acquired; {@code false} if timed out
* @throws InterruptedException if the current thread is interrupted
*/
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquireShared(arg) >= 0 ||
doAcquireSharedNanos(arg, nanosTimeout);
}
/**
* Releases in shared mode. Implemented by unblocking one or more
* threads if {@link #tryReleaseShared} returns true.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryReleaseShared} but is otherwise uninterpreted
* and can represent anything you like.
* @return the value returned from {@link #tryReleaseShared}
*/
/**
* 释放共享锁资源
* @param arg 释放的资源数量
* @return 是否释放成功
*/
public final boolean releaseShared(int arg) {
// 尝试释放arg个资源,判断释放完后是否还有资源占用
if (tryReleaseShared(arg)) {
// 如果是否后没有资源被占用,则将同步队列中的节点释放
doReleaseShared();
return true;
}
return false;
}
// Queue inspection methods
/**
* Queries whether any threads are waiting to acquire. Note that
* because cancellations due to interrupts and timeouts may occur
* at any time, a {@code true} return does not guarantee that any
* other thread will ever acquire.
*
* <p>In this implementation, this operation returns in
* constant time.
*
* @return {@code true} if there may be other threads waiting to acquire
*/
public final boolean hasQueuedThreads() {
return head != tail;
}
/**
* Queries whether any threads have ever contended to acquire this
* synchronizer; that is if an acquire method has ever blocked.
*
* <p>In this implementation, this operation returns in
* constant time.
*
* @return {@code true} if there has ever been contention
*/
public final boolean hasContended() {
return head != null;
}
/**
* Returns the first (longest-waiting) thread in the queue, or
* {@code null} if no threads are currently queued.
*
* <p>In this implementation, this operation normally returns in
* constant time, but may iterate upon contention if other threads are
* concurrently modifying the queue.
*
* @return the first (longest-waiting) thread in the queue, or
* {@code null} if no threads are currently queued
*/
public final Thread getFirstQueuedThread() {
// handle only fast path, else relay
return (head == tail) ? null : fullGetFirstQueuedThread();
}
/**
* Version of getFirstQueuedThread called when fastpath fails
*/
private Thread fullGetFirstQueuedThread() {
/*
* The first node is normally head.next. Try to get its
* thread field, ensuring consistent reads: If thread
* field is nulled out or s.prev is no longer head, then
* some other thread(s) concurrently performed setHead in
* between some of our reads. We try this twice before
* resorting to traversal.
*/
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's next field might not have been set yet, or may have
* been unset after setHead. So we must check to see if tail
* is actually first node. If not, we continue on, safely
* traversing from tail back to head to find first,
* guaranteeing termination.
*/
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;
}
/**
* Returns true if the given thread is currently queued.
*
* <p>This implementation traverses the queue to determine
* presence of the given thread.
*
* @param thread the thread
* @return {@code true} if the given thread is on the queue
* @throws NullPointerException if the thread is null
*/
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;
}
/**
* Returns {@code true} if the apparent first queued thread, if one
* exists, is waiting in exclusive mode. If this method returns
* {@code true}, and the current thread is attempting to acquire in
* shared mode (that is, this method is invoked from {@link
* #tryAcquireShared}) then it is guaranteed that the current thread
* is not the first queued thread. Used only as a heuristic in
* ReentrantReadWriteLock.
*/
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
/**
* 结果为false
* 1. h==t 头尾引用相等,说明当前队列无节点或只有一个节点。两种情况下,新节点入队后都可以直接去尝试获取锁,不需要等待。(只有一个节点时,该节点可能正在释放锁)
* 2. 队列中有两个及以上节点 && h.next != null && s.thread == Thread.currentThread()
*/
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
// Instrumentation and monitoring methods
/**
* Returns an estimate of the number of threads waiting to
* acquire. The value is only an estimate because the number of
* threads may change dynamically while this method traverses
* internal data structures. This method is designed for use in
* monitoring system state, not for synchronization
* control.
*
* @return the estimated number of threads waiting to acquire
*/
public final int getQueueLength() {
int n = 0;
for (Node p = tail; p != null; p = p.prev) {
if (p.thread != null)
++n;
}
return n;
}
/**
* Returns a collection containing threads that may be waiting to
* acquire. Because the actual set of threads may change
* dynamically while constructing this result, the returned
* collection is only a best-effort estimate. The elements of the
* returned collection are in no particular order. This method is
* designed to facilitate construction of subclasses that provide
* more extensive monitoring facilities.
*
* @return the collection of threads
*/
public final Collection<Thread> getQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
return list;
}
/**
* Returns a collection containing threads that may be waiting to
* acquire in exclusive mode. This has the same properties
* as {@link #getQueuedThreads} except that it only returns
* those threads waiting due to an exclusive acquire.
*
* @return the collection of threads
*/
public final Collection<Thread> getExclusiveQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (!p.isShared()) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
}
return list;
}
/**
* Returns a collection containing threads that may be waiting to
* acquire in shared mode. This has the same properties
* as {@link #getQueuedThreads} except that it only returns
* those threads waiting due to a shared acquire.
*
* @return the collection of threads
*/
public final Collection<Thread> getSharedQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (p.isShared()) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
}
return list;
}
/**
* toString
* @return str
*/
public String toString() {
int s = getState();
String q = hasQueuedThreads() ? "non" : "";
return super.toString() +
"[State = " + s + ", " + q + "empty queue]";
}
/**
* 判断节点是否在同步队列中
* @param node 节点
* @return 是否
*/
final boolean isOnSyncQueue(Node node) {
// 如果节点状态为CONDITION或者node是头,则它一定不在同步队列中
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 如果节点有后继者,则一定在同步队列中,因为next是用在同步队列中节点相连。
if (node.next != null)
return true;
// 从队尾往前找,判断node是否在同步队列中
return findNodeFromTail(node);
}
/**
* 在同步队列中,从队尾往前找node,如果找到返回true,否则false
* @param node 某节点
* @return 是否存在
*/
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
/**
* 当节点被唤醒后,尝试将其从条件等待队列放到同步队列中
* @param node 节点
* @return 是否成功
*/
final boolean transferForSignal(Node node) {
// 尝试将node的状态从CONDITION变为0,如果失败返回false
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 尝试将node放到同步等待队列中,p是原先的尾节点
Node p = enq(node);
// 获取p的waitStatus状态
int ws = p.waitStatus;
// 如果node前一个节点p的waitStatus 为CANCELLED 或者 将前一个节点状态变为SIGNAL失败
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
// 唤醒node的线程
LockSupport.unpark(node.thread);
// 返回成功
return true;
}
/**
* 如果有必要的话,取消等待后,迁移节点到同步队列
* 如果线程在被唤醒前取消的话返回true
*/
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
/*
* If we lost out to a signal(), then we can't proceed
* until it finishes its enq(). Cancelling during an
* incomplete transfer is both rare and transient, so just
* spin.
*/
// 如果节点不在同步队列里,就尝试让出CPU资源
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
/**
* 完全释放
* @param node 节点
* @return 释放的资源数
*/
final int fullyRelease(Node node) {
boolean failed = true;
try {
// 装填
int savedState = getState();
// 释放所有资源,唤醒同步队列头结点之后的节点
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
// 释放失败时,当前节点的状态为CANCELLED
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
// Instrumentation methods for conditions
/**
* Queries whether the given ConditionObject
* uses this synchronizer as its lock.
*
* @param condition the condition
* @return {@code true} if owned
* @throws NullPointerException if the condition is null
*/
public final boolean owns(ConditionObject condition) {
return condition.isOwnedBy(this);
}
/**
* Queries whether any threads are waiting on the given condition
* associated with this synchronizer. Note that because timeouts
* and interrupts may occur at any time, a {@code true} return
* does not guarantee that a future {@code signal} will awaken
* any threads. This method is designed primarily for use in
* monitoring of the system state.
*
* @param condition the condition
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if exclusive synchronization
* is not held
* @throws IllegalArgumentException if the given condition is
* not associated with this synchronizer
* @throws NullPointerException if the condition is null
*/
public final boolean hasWaiters(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.hasWaiters();
}
/**
* Returns an estimate of the number of threads waiting on the
* given condition associated with this synchronizer. Note that
* because timeouts and interrupts may occur at any time, the
* estimate serves only as an upper bound on the actual number of
* waiters. This method is designed for use in monitoring of the
* system state, not for synchronization control.
*
* @param condition the condition
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if exclusive synchronization
* is not held
* @throws IllegalArgumentException if the given condition is
* not associated with this synchronizer
* @throws NullPointerException if the condition is null
*/
public final int getWaitQueueLength(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitQueueLength();
}
/**
* Returns a collection containing those threads that may be
* waiting on the given condition associated with this
* synchronizer. Because the actual set of threads may change
* dynamically while constructing this result, the returned
* collection is only a best-effort estimate. The elements of the
* returned collection are in no particular order.
*
* @param condition the condition
* @return the collection of threads
* @throws IllegalMonitorStateException if exclusive synchronization
* is not held
* @throws IllegalArgumentException if the given condition is
* not associated with this synchronizer
* @throws NullPointerException if the condition is null
*/
public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitingThreads();
}
/**
* 条件对象
*/
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
private transient Node firstWaiter;
private transient Node lastWaiter;
public ConditionObject() { }
/**
* 将当前线程封装成条件节点加进条件等待队列中
* @return 封装的当前节点
*/
private Node addConditionWaiter() {
// 队尾
Node t = lastWaiter;
// 如果队尾节点被取消,清除。条件等待队列中的节点除了CONDITION就是CANCELLED
if (t != null && t.waitStatus != Node.CONDITION) {
// 清除队列中被取消的节点
unlinkCancelledWaiters();
// 重新将t指向尾节点
t = lastWaiter;
}
// 创建一个waitStatus为CONDITION的节点
Node node = new Node(Thread.currentThread(), Node.CONDITION);
// 如果队列中没有节点,则当前节点为头结点
if (t == null)
firstWaiter = node;
// 否则拼到队尾
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
/**
* 不断尝试将条件等待队列中的节点移动到同步等待队列中,并移除队首
* 一次只移动一个
*/
private void doSignal(Node first) {
do {
// 如果等待队列中只有一个节点,将尾指针置为null
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
// 将first移除队列
first.nextWaiter = null;
// 如果尝试将其从条件等待队列移向同步等待队列成功,则停止循环
// 如果失败,则重新将first赋值为firstWaiter,并判断其不为null,再次进入循环
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
/**
* 将条件等待队列中所有的节点移动到同步等待队列中
* @param first (non-null) 条件队列的队头
*/
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
// 从队首开始往后移动指针,挨个移到同步等待队列
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
/**
* 清除等待队列中被取消的节点
*/
private void unlinkCancelledWaiters() {
// 队头
Node t = firstWaiter;
// 追踪节点,看做t的前序节点
Node trail = null;
while (t != null) {
// t的下个节点
Node next = t.nextWaiter;
// 如果t的状态不是CONDITION。t被取消了
if (t.waitStatus != Node.CONDITION) {
// 拆离t的后继节点
t.nextWaiter = null;
// trail没被更新过,说明头结点已经被取消。则将头设为next
if (trail == null)
firstWaiter = next;
// 否则从链表中刨除当前节点
else
trail.nextWaiter = next;
// 如果next为null,则说明t为尾节点,则将尾节点指向前序节点。
if (next == null)
lastWaiter = trail;
}
// 否则trail为t的前一个节点
else
trail = t;
// 指针后移
t = next;
}
}
/**
* 移动条件等待队列的队头到同步等待队列中
*/
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);
}
/**
* Implements uninterruptible condition wait.
* <ol>
* <li> Save lock state returned by {@link #getState}.
* <li> Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
* <li> Block until signalled.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* </ol>
*/
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();
}
/*
* For interruptible waits, we need to track whether to throw
* InterruptedException, if interrupted while blocked on
* condition, versus reinterrupt current thread, if
* interrupted while blocked waiting to re-acquire.
*/
/** Mode meaning to reinterrupt on exit from wait */
private static final int REINTERRUPT = 1;
/** Mode meaning to throw InterruptedException on exit from wait */
private static final int THROW_IE = -1;
/**
* Checks for interrupt, returning THROW_IE if interrupted
* before signalled, REINTERRUPT if after signalled, or
* 0 if not interrupted.
*
* 如果是收到信号前中断,node.waitStatus一定为CONDITION,返回THROW_IE
* 如果是收到信号后中断,
*/
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
/**
* 根据中断模式进行中断
* @param interruptMode 中断模式
* @throws InterruptedException 异常
*/
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
// THROW_IE模式抛出异常
if (interruptMode == THROW_IE)
throw new InterruptedException();
// REINTERRUPT模式会中断当前线程
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)) {
// 阻塞当前线程,等待signal唤醒或者同步队列中前驱节点唤醒 todo
LockSupport.park(this);
// 假如被中断过,则在这里退出循环
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 如果node是同步队列的头的后继节点并且尝试获取对应的资源数成功,并且获取的过程中被中断过 并且中断模式不为THROW_IE,设置中断模式为REINTERRUPT
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
// 如果node有nextWaiter,则将条件队列中CANCELLED的节点移除队列 todo 为啥
if (node.nextWaiter != null)
unlinkCancelledWaiters();
// 如果中断模式不为0,说明需要中断
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/**
* Implements timed condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <li> Save lock state returned by {@link #getState}.
* <li> Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
* <li> Block until signalled, interrupted, or timed out.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
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();
}
/**
* Implements absolute timed condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <li> Save lock state returned by {@link #getState}.
* <li> Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
* <li> Block until signalled, interrupted, or timed out.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
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;
}
/**
* Implements timed condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <li> Save lock state returned by {@link #getState}.
* <li> Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
* <li> Block until signalled, interrupted, or timed out.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
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;
}
// support for instrumentation
/**
* Returns true if this condition was created by the given
* synchronization object.
*
* @return {@code true} if owned
*/
final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
return sync == AbstractQueuedSynchronizer.this;
}
/**
* Queries whether any threads are waiting on this condition.
* Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
*
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
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;
}
/**
* Returns an estimate of the number of threads waiting on
* this condition.
* Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
*
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
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;
}
/**
* Returns a collection containing those threads that may be
* waiting on this Condition.
* Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
*
* @return the collection of threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
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;
}
}
/**
* Setup to support compareAndSet. We need to natively implement
* this here: For the sake of permitting future enhancements, we
* cannot explicitly subclass AtomicInteger, which would be
* efficient and useful otherwise. So, as the lesser of evils, we
* natively implement using hotspot intrinsics API. And while we
* are at it, we do the same for other CASable fields (which could
* otherwise be done with atomic field updaters).
*/
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);
}
}