它的所有子类中,要么实现并使用了它独占功能的API,要么使用了共享锁的功能,而不会同时使用两套API,即便是最有名的子类ReentrantReadWriteLock,也是通过两个内部类:读锁和写锁来实现的。
ReentranctLock类主要靠两个内部类实现(FairSync/NonfairSync),这两个类都继承了AQS。 ReentrantLock是AQS独占功能的实现。
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;
//后继节点的线程处于等待状态,而当前节点的线程如果释放了同步状态或者被取消,
//将唤醒后继节点。当前节点的后继节点已经(或即将)被阻塞(通过park,取消线程许可,使其阻塞),所以当当前释放或者被取消的时候,一定要unpark(使当前线程获取许可)它的后继节点。
static final int CONDITION = -2;
//当前节点在等待condition,也就是在condition(条件)的等待队列中,
//当其它线程对Condition调用signal()方法后,
//该节点将从等待队列转移到同步队列中(waitStatus值变为0),加入对同步队列锁的获取中。
static final int PROPAGATE = -3;
//表示当前场景下后续的acquireShared能够得以执行。 共享模式下的锁释放操作应该被传播到其它节点。该状态值在doReleaseShared方法中被设置。
volatile int waitStatus; //同步状态
//上面几个常量表示线程的几个状态, 当waitStatus==0,表示当前节点在Condition的锁池中等待获取同步状态
//该状态值为了简便使用,所以使用了数值类型。
//非负数值意味着该节点不需要被唤醒(1表示取消线程,0表示正在获取锁)。
//所以大多数代码并不需要检查该状态的确定值,只需要根据正负即可。
//对于一个正常的Node,它的初始值为0
//对于一个condition队列中的Node,他的初始值为Condition。(如果修改这个值,可以通过AQS提供的CAS修改)
---------------------------------------------------
volatile Node prev;
//前驱结点。当前结点依赖前前驱结点来检查waitStatus,
//前驱节点是在当前队列入队时被设置的。
//为了提高GC效率,当前节点在出队时,会把前驱结点设置为null。
//而且在取消前驱结点中,则会循环一直找到一个非取消的节点,
//因为头节点是永远不会被取消的,所以一定能找到。
volatile Node next;
//后继节点,在当前节点释放时唤醒后继节点。该后继节点也是在入队时被分配的。
//当前节点被取消时,会重新调整链表节点指向关系。如:节点入队操作完成前,
//入队操作的并未设置前驱结点的后继结点。所以会看到前驱结点的后继结点为null,
//但是这不意味着前驱结点就是队列的尾结点,如果后继结点为null,我们可以通过尾结点
//向前扫描来做双重检测。一个被取消的结点的后继设置为自身(node.next=node)。
//这样设置会帮助isOnSyncQueue的执行效率。(该方法使用 if(node.next!=node))
volatile Thread thread; //当前结点的线程。
Node nextWaiter;
//代表Condition等待队列链表的后继结点或者代表共享模式的结点SHARED。
// condition条件队列:因为condition队列只能在独占模式下被访问,
//我们只需要简单的使用链表队列来链接正在等待条件的结点。在然后他们会被转移到
//同步队列(AQS队列)再次重新获取。
//由于条件队列只能在独占模式下使用,所以我们要表示共享模式的结点的话,
//只要使用特殊值SHATED来表明即可。
//判断是不是共享线程,
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;
}
//用于Condition条件等待队列构造结点
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
在初始化的AQS队列中,head和tail默认为null。
private transient volatile Node head;
//等待队列的head节点,只有当调用的setHead方法的时候才进行加载,属于懒加载。
//head结点表示正在运行的线程
private transient volatile Node tail; //等待状态的尾节点
private volatile int state; //AQS队列的状态,<0表示溢出 =0表示锁空闲 >0表示锁重入次数。
/*
* 该方法首先会调用子类重写的tryAcquire方法来获取同步状态,当获取失败后,
* 会调用addWaiter来构造同步结点,并将结点加入到同步队列的队尾
* 最后调用acquireQueue方法自旋获取同步状态。
*/
//以独占模式获取对象,忽略中断,也就是不响应中断
public final void acquire(int arg) { //此方法一般由子类调用
if (!tryAcquire(arg) && //一般子类会重写此方法 当前线程没有获取锁,
//没有获得锁才会进入&&后半部分
acquireQueued( //自旋获取锁的过程,
addWaiter(Node.EXCLUSIVE), arg))
//将未获取锁的线程加入到等待队列,Node.EXCLUSIVE用来标识此结点为独占模式结点
selfInterrupt(); //触发中断
}
//以独占模式获取对象,如果被中断则中止
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
//当前线程在超时时间内没有获取到同步状态,那么返回false 获取到返回true
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
// 将当前线程添加到同步队列中
/*
* 首先构造一个独占式Node,pred!=null判断同步是否为空,
* 如果不为空,则通过compareAndSetTail将节点线程安全的添加到队尾
* 如果pred==null或者CAS添加失败,则调用enq方法通过死循环来添加节点
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //构建独占式Node
Node pred = tail; //尾结点
if (pred != null) { //如果不为空,则同步队列中存在节点
node.prev = pred;//当前节点连接tail,线程私有变量,无法被修改,因此不需要CAS
if (compareAndSetTail(pred, node)) { //CAS更新尾节点
pred.next = node; //tail连接当前节点
return node;
}
}
enq(node); //队列中无元素或者CAS操作设置尾节点不成功
return node;
}
//死循环添加节点
/*
* 先判断队列是否为空,如果为空则构造一个空节点,并将队列的首节点和尾节点设置为当前节点
* 这样再一次进入循环后,将直接进入else语句通过CAS设置尾节点。
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail; //尾节点
if (t == null) { //尾节点为空,证明head==null,说明同步队列还未初始化
if (compareAndSetHead(new Node()))
//构造一个空node并CAS将其赋给head
tail = head;//只有一个节点时,头尾节点相同
} else {
node.prev = t; //当前节点前驱连接tail
//这步不需要CAS,因为node是线程自行构建的,别的线程无法修改
if (compareAndSetTail(t, node)) { //CAS设置新的尾节点
t.next = node;
return t;
}
}
}
}
/* 当同步节点成功添加进同步队列后,此方法进入一个自旋的个过程
*每个节点(对应的线程)都在自省的观察,当条件满足,获取到同步状态,就从自旋状态退出
*否则依然留在自旋过程中(并阻塞节点的线程),
*/
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); //设置新节点
//设置前驱结点的后继结点为null,使前驱结点成为不可达,方便回收
p.next = null; // help GC
failed = false;
// 返回当前线程是否被中断
return interrupted;
}
// 对前驱节点进行状态设置且调用park方法阻塞当前线程
//
if (shouldParkAfterFailedAcquire(p, node) && //设置前驱节点的状态
parkAndCheckInterrupt()) //park阻塞(挂起)当前线程
// 说明当前线程是被中断唤醒的。
// 除非碰巧线程中断后acquire成功了,那么根据Java的最佳实践,
// 需要重新设置线程的中断状态(acquire.selfInterrupt)
interrupted = true;
}
} finally {
if (failed) //获得同步状态
cancelAcquire(node); //在等待队列中取消当前节点
}
}
//将CANCELLED = 1(等待超时或者被中断的线程从等待线程出队);
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; //前驱结点的同步状态
if (ws == Node.SIGNAL) //前驱被释放,后继被唤醒
return true;
// 过滤掉所有ws > 0的前驱节点,即CANCELLED = 1的节点
// 节点在初始化时waitStatus值为0
if (ws > 0) { //取消掉所有超时等待或者被唤醒的线程
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 将前驱结点的状态设置为Node.SIGNAL,表示其后继结点需要被唤醒
// 0 或 PROPAGATE (CONDITION用在ConditonObject,这里不会是这个值)
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
// 返回为false让线程先不要阻塞
// 再次判断前驱节点是否为首节点,并获取同步状态,如果获取失败,才阻塞线程
return false;
}
//阻塞当前线程,直到被前驱唤醒或者被中断
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted(); //当前线程中断为标志
}
public class LockSupport {
//为了线程调度,在许可可用之前,禁用当前线程
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); //设置阻塞状态
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
//设置阻塞状态
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
}
当线程获取到同步状态并执行了相关逻辑之后,需要释放同步状态,并且使后续结点能够获取同步状态。调用同步器的release方法可以释放同步状态,该方法在释放同步状态后会唤醒其后继结点(使后继结点重新尝试获取同步方法)
//独占式的释放同步状态,并且在释放同步状态后将同步队列中第一个节点包含的线程唤醒
public final boolean release(int arg) {
if (tryRelease(arg)) { //由对应子类实现,表示释放锁成功
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); //唤醒后继节点线程 //唤醒首结点的后继线程
return true;
}
return false;
}
// 删除当前结点
/*
* 分为三种情况:
* 1,要删除节点为尾结点:将前驱置为尾节点
* 2,当前节点为中间节点,且前驱后缀都需要获得同步状态 :前驱后缀相连
* 3,非前两种情况,解除后面节点的阻塞状态
*/
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null; //将结点线程置为0;
// Skip cancelled predecessors
Node pred = node.prev;
//删除所有当前结点前驱中所有线程状态被中断或者被取消的节点
while (pred.waitStatus > 0) 从当前节点往前查找
node.prev = pred = pred.prev;
Node predNext = pred.next;//前驱的后缀
node.waitStatus = Node.CANCELLED; //当前结点状态置为结束状态
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) {
//当前结点为尾结点,并且将当前结点的前驱设为新的尾结点
compareAndSetNext(pred, predNext, null); //将前驱的后缀(node)设为null
} else { //非尾结点
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
//前驱和后继都需要获取同步状态,那么将他们两个连接在一起,达到删除当前结点的目的
if (pred != head && 前驱不是头结点
((ws = pred.waitStatus) == Node.SIGNAL ||
//前驱的waitStatus是-1(退出同步唤醒后继结点)
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
//waitStatus不是1(线程已退出争夺同步状态)将其设置为SIGNAL
pred.thread != null) { //前驱的结点不为空
Node next = node.next;
if (next != null && next.waitStatus <= 0)
//当前结点有后继结点,并且当前结点处于获取同步状态
compareAndSetNext(pred, predNext, next);
//将前驱和后继连接起来,达到删除当前结点的目的
} else {
unparkSuccessor(node);
//解除当前结点后一个结点的阻塞状态,从而达到删除当前结点的目的
}
node.next = node; // help GC
}
}
//唤醒后继结点
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) //<=表示线程仍然处于等待状态,
//通过遍历找到离head最近的等待结点
s = t;
}
if (s != null) //s==null表示同步队列没有需要同步的线程了
LockSupport.unpark(s.thread); //解除此线程的阻塞状态;
}