首先类看一下AQS的静态内部类Node
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;
/** 这个常量代表线程正在等待condition */
static final int CONDITION = -2;
/**
* 这个常量代表下一个acquireShard(获取共享锁)要无条件传播?
*/
static final int PROPAGATE = -3;
/**
* 这个变量代表等待变量,它的值只能取上面定义的几个常量CANCELLED ,SIGNAL,CONDITION ,PROPAGATE
*/
volatile int waitStatus;
/**
* 这个变量指向前一个节点,可以看出Node是双向链表中一个节点的数据类型
*/
volatile Node prev;
/**
* 这个变量指向后一个节点
*/
volatile Node next;
/**
* 线程,为了将线程放入队列中管理起来,用队列的节点Node包装了线程
*/
volatile Thread thread;
/**
* 指下一个等待condition的node,不知道怎么等待condition
*/
Node nextWaiter;
/**
* 如果nextWaiter == SHARED就说明是共享节点
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 获取前一个节点Node
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // 这个构造方法通常用来构造列表头结点或者共享节点
}
Node(Thread thread, Node mode) { // 用于构造等待队列的节点
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // 用到condition的时候用
this.waitStatus = waitStatus;
this.thread = thread;
}
}
AQS的变量
/**
* 等待队列的头结点
*/
private transient volatile Node head;
/**
* 等待队列的尾节点
*/
private transient volatile Node tail;
/**
* AQS维护的状态值,表示当前线程获取锁的次数
*/
private volatile int state;
/**
* 这是线程自旋的等待时间,单位是纳秒
*/
static final long spinForTimeoutThreshold = 1000L;
AQS的变量很简单,就首尾节点和状态值,而它的成员方法就是对等待队列和状态值的操作。
AQS成员方法解读
compareAndSetState
protected final boolean compareAndSetState(int expect, int update) {
// 这里用的是native方法,不做深入
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
这个方法的用CAS的方式修改state值,而state是volatile修饰的,因此在多线程的情况下也能够保证线程安全。
compareAndSetHead、compareAndSetTail
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
这两个方法也是用CAS线程安全的方式设置AQS的等待队列头尾节点
compareAndSetWaitStatus
private static final boolean compareAndSetWaitStatus(Node node,
int expect,
int update) {
return unsafe.compareAndSwapInt(node, waitStatusOffset,
expect, update);
}
这个方法也是用CAS线程安全的方式设置节点的状态waitStatus
compareAndSetNext
private static final boolean compareAndSetNext(Node node,
Node expect,
Node update) {
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
用于设置Node的next成员变量
setHead
private void setHead(Node node) {
head = node;
// 为什么头节点中没有线程呢?
node.thread = null;
// 因为是头节点,所以前面不会有节点
node.prev = null;
}
将一个节点设置为队列的头节点
enq
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;
}
}
}
}
这个方法的作用就是向等待队列插入节点,注意这个方法如果插入不成功就会不断尝试直到成功为止
addWaiter
private Node addWaiter(Node mode) {
// 将当前线程创建一个新节点
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
// 先试着插入一次,插入成功就返回插入的节点,不成功就用enq插到成功为止
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
这个方法还是将节点插入到等待队列,比enq多出一步创建节点而已
unparkSuccessor
private void unparkSuccessor(Node node) {
/*
* 如果节点的状态为负数即SIGNAL,CONDITION ,PROPAGATE,就把状态清零
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* 找到该节点后面一个处于阻塞状态(SIGNAL,CONDITION ,PROPAGATE)的节点,将它包含的线程唤醒
*/
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); // 唤醒线程
}
该方法的作用就是唤醒当前节点后面一个被阻塞节点中的线程
doReleaseShared
private void doReleaseShared() {
for (;;) {
Node h = head;
// 如果头节点的状态为,SIGNAL唤醒头节点后面的一个阻塞节点
if (h != null && h != tail) {
int ws = h.waitStatus;
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) // 这里通过一个for循环来保证线程安全性
break;
}
}
这个方法貌似用于释放共享锁,不明白为什么唤醒头节点后面的线程就可以释放共享锁?
setHeadAndPropagate
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // 保留前一个头节点
setHead(node); // 设置新的节点为头节点
/*
* propagate 是tryAcquireShared返回的值,不知道表示什么,这里的逻辑还不明确
*
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
该方法的作用是:1、设置头节点。2、如果后继节点处于共享阻塞状态就释放共享锁?
cancelAcquire
/**
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
// 从当前节点向前找,找到状态不为取消CANCELLED的节点pred
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 保存pred节点的下个节点
Node predNext = pred.next;
// 将当前节点的状态设置为CANCELLED
node.waitStatus = Node.CANCELLED;
// 写了一大堆,要做的就是把当前节点到pred节点中间的所有节点从等待队列移除
if (node == tail && compareAndSetTail(node, pred)) {
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.
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; // 使得当前节点不可达,让GC
}
}
这个方法的作用就是移除等待队列中的节点
shouldParkAfterFailedAcquire
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 {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
这个方法主要的目的是当该线程尝试获取锁失败后,判断该线程是否应该进入阻塞,如果前一个节点的状态为waitStatus就进入阻塞,如果不是就继续尝试获取锁。
parkAndCheckInterrupt
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
阻塞线程,并且判断线程是否中断
acquireQueued
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; // help GC
failed = false;
return interrupted;
}
// 获取失败就进入阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
这个方法表示等待队列中的节点会去尝试获取锁,获取到的成为头节点,获取失败的则线程继续被阻塞。
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);
}
}
这个方法与acquireQueued很像,区别在于它获取不到会抛出异常
doAcquireNanos
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);
}
}
这个方法获取不到锁会等待nanosTimeout纳秒再去尝试获取,还是获取不到就返回,不会阻塞。
doAcquireShared
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);
}
}
共享模式获取锁的时候在等待队列中添加的节点都是一个单例Node.SHARED
doAcquireSharedInterruptibly
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);
}
}
中断模式的获取共享锁
doAcquireSharedNanos
private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
long lastTime = System.nanoTime();
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;
}
}
if (nanosTimeout <= 0)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now;
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
超时模式的获取共享锁
acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
这个方法的就是用来获取独占锁的,如果一次获取失败,那么久不断尝试获取直到获取成功。
acquireInterruptibly
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
这个方法的就是用来响应中断地获取独占锁的,如果一次获取失败,那么久不断尝试获取直到获取成功或者遇到中断。
tryAcquireNanos
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
这个方法获取独占锁,直到获取成功或遇到中断,或时间到
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;
}
这个方法用于释放锁
acquireShared
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
不可中断的方式获取共享锁
acquireSharedInterruptibly
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
响应中断的方式获取共享锁
tryAcquireSharedNanos
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquireShared(arg) >= 0 ||
超时的方式获取共享锁
releaseShared
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
释放共享锁