目录
AQS笔记一 ---- 部分源码分析
AQS(AbstractQueuedSynchronizer) 队列同步器, AQS定义了一套多线程访问共享资源的同步器框架.
AQS 内部依赖的同步队列(一个FIFO双向队列)来完成同步状态的管理, 当前线程获取同步状态失败时, 同步器会将当前线程以及等待状态等信息构成一个节点(Node) 并将其加入到同步队列, 同时阻塞当前线程, 当同步状态释放时, 会将首节点中的线程唤醒, 使其再次尝试获取同步状态.
注: 以下源码基于jdk1.8
一、内部类, Node节点
Node类, 定义了同步队列中的节点对象, waitStatus等待状态, thread记录线程对象引用;
static final class Node {
/** Marker to indicate a node is waiting in shared mode */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus; // 等待状态
volatile Node prev; // 前继节点
volatile Node next; // 后继节点
volatile Thread thread; // 记录线程引用
// nextWaiter为SHARED时, 表示共享模式, 为EXCLUSIVE时, 表示排他模式
Node nextWaiter;
}
waitStatus取值:
- CANCELLED: 值为1, 在同步队列中等待的线程等待超时或者被中断, 表示结束状态, 进入该状态后的节点将不会再变化,
- 0状态, 值为0, 表示初始化状态;
- SIGNAL: 值为-1, 此状态的节点, 处于等待唤醒状态,当其前继节点的线程释放了同步锁或被取消后, 会通知该后继节点线程执行; 即: 只要前继节点释放锁后, 就会通知标识为SIGNAL状态的后继节点的线程执行;
- CONDITION: 值为-2, 与Condition相关, 该标识的节点处于等待队列中, 节点的线程等待在Condition上, 其他线程调用Condition的signal()方法后, CONDITION状态的节点将从等待队列转移到同步队列中, 等待获取同于锁;
- PROPAGATE: 值为-3, 与共享模式相关, 在共享模式中, 该状态标识的节点的线程处于可运行状态;
AQS在判断状态时, 通过用waitStatus>0表示取消状态, waitStatus< 0表示有效状态
二、AQS成员变量
AbstractQueuedSynchronizer中定义偏移量的原因, 是为了其他线程被阻塞的情况下, 通过当前线程调用Unsafe类的方法改变那个线程属性值;
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable
{
private volatile int state; // 同步状态
private transient volatile Node head; // 同步队列头节点
private transient volatile Node tail; // 同步队列尾节点
private static final Unsafe unsafe = Unsafe.getUnsafe(); // 获取Unsafe实例
private static final long stateOffset; // 记录state在AQS类中的偏移量
private static final long headOffset; // 记录head在AQS类中偏移量
private static final long tailOffset; // 记录tail在AQS类中偏移量
private static final long waitStatusOffset; //记录waitStatus在Node类中偏移量
private static final long nextOffset; // 记录 next在Node类中偏移量
// 初始化那些偏移量值
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); }
}
}
三、源码分析
AQS源码分析主要分析排他式同步状态获取释放
和 共享式同步状态获取释放
- acquire/relese
- acquireShare/releaseShare
2.1 排他式同步状态获取释放
2.1.1 acquire(int arg)
独占式同步状态获取流程:
// 尝试获取同步状态, 成功则返回;
// 失败则将当前线程以排他模式添加到同步队列队尾, 然后进入自旋状态, 若在自旋过程中被中断, 则会调用selfInterrupt()将自己中断掉;
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // EXCLUSIVE表示这个节点为排他模式
selfInterrupt(); // 将当前线程中断
}
// 将当前线程中断
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
// 尝试获取同步位, 交由子类实现
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
// 将当前线程和mode包装成一个Node对象node, 然后将node添加到同步队列尾部, 最后返回node;
private Node addWaiter(Node mode) {
// 获取当前线程, 将mode的值赋给nextWaiter
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
// 尾节点不为空, 使用CAS算法将node更新为尾节点, 然后返回node
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node); // 尾节点为空, 调用enq方法将node添加到队列尾部
return node;
}
// 若队列尾节点为空, 即队列为空, 则创建一个无状态的Node对象作为尾节点, 然后将node添加到同步队列尾部
private Node enq(final Node node) {
for (;;) { // 失败重试
Node t = tail;
// 尾节点为空, 创建一个无状态的Node对象, 初始化队列
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else { // 然后把node节点添加到队列尾部, 并返回
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
// 使用unsafe类的compareAndSwapObject将tail更新为update
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
// 自旋请求同步状态, 若自旋过程中被中断, 则返回true, 否则返回false;
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)) { // 若前继节点为头结点, 并且当前线程(即:node保存的线程)获取到同步状态
setHead(node); // 将自己设置为头结点
p.next = null; // help GC
failed = false;
return interrupted; // 返回在自旋过程中是否被中断
}
// 若node的前继节点为等待唤醒状态(SIGNAL), 且 等待唤醒过程中被中断, interrupted才会被设置为true
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// 若前继节点状态为等待唤醒状态, 返回true
// 若前继节点状态大于0, 则删除状态大于0的前继节点; 若前继节点状态为其他状态, 则将其状态设置为等待唤醒状态; 返回false
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) // node的前继节点处于等待唤醒状态, 返回true
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
// node前继节点状态大于0, 表示前继节点线程已经运行结束或者被中断
// 将状态大于0的前继节点删除
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
// 前继节点状态为其他状态, 比如: 0, -2(CONDITION), -3(PROPAGATE), 将node状态设置为等待唤醒状态
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
// 使当前线程进入等待, 等待过程中被LockSupport.unpark()唤醒, 或者 被其他线程中断后, 才会继续向下运行
// 返回当前线程中断状态, 并且刷新中断状态
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); // 当前线程进入等待
return Thread.interrupted();
}
// 取消node节点获取资源, 将node状态设置为1(CANCELLED), 如果头结点不为空(...), 则将node节点从同步队列中删除;
// 头结点为空, 则唤醒下一个后继节点
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
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节点的条件
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
2.1.2 relese(int arg)
// 释放同步状态, 释放成功则唤醒下一个后继节点, 返回true; 释放失败返回false
public final boolean release(int arg) {
if (tryRelease(arg)) { // 尝试释放同步状态
Node h = head; // 获取队列头结点
// 头结点不为空, 且状态不为0, 唤醒下一个同步节点
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
// 唤醒下一个后继节点
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus; // 获取节点等待状态
// 将其状态更新为0, 等待状态小于0表示为有效状态, 大于0表示线程已经结束或被中断
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
// 若后继节点为空 或者后继节点状态大于0, 则从尾节点向前遍历, 找到最前面状态小于等于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;
}
// s为从tail向前遍历最前面的状态小于等于0的节点
if (s != null)
LockSupport.unpark(s.thread); // s 不为null, 则将 s节点中存放的线程唤醒
}
2.2 共享式同步状态获取释放
2.1.1 acquireShared(int arg)
// 尝试获取同步状态小于0,
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
// 由子类实现, 共享方式尝试获取共享状态
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
// 自旋获取同步状态
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED); // 以共享模式将当前线程添加到队尾
boolean failed = true; // 是否获取失败标识
try {
boolean interrupted = false; // 记录获取共享状态过程中是否被中断过
for (;;) {
// 获取前继节点, 若前继节点为null, 抛出异常
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);
}
}
// 将当前线程和mode模式包装成Node节点, 添加到同步队列尾部
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
// 若队尾节点不为null, 使用CAS操作, 将node更新到队尾, 返回node
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
// 若同步队列为null, 则初始化同步队列, 然后将node添加到队列尾部;
// 若同步队列不为null, 则将node节点添加到队列尾部
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// 若队列为空, 初始化队列,
if (t == null) { // Must initialize
if (compareAndSetHead(new Node())) // 通过CAS操作设置队列头部
tail = head; // 将头部节点赋值给尾部
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node); // 将node节点的引用赋给head节点
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
// 获取的资源数大于0, 或者之前的头结点为null, 或者之前的头结点状态小于0,
// 或者当前的头结点为null, 或者当前头结点状态小于0,
// 若下一个后继节点不为空, 或者下一个后继节点为共享模式节点, 则唤醒下一个节点
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
// 若头结点状态不为0, 则将头结点状态置为PROPAGATE,成功则返回, 失败重试;
// 若头结点状态为SIGNAL, 则将头结点状态置为0, 成功则唤醒下一后继节点, 然后返回 失败则重试;
// 失败重试之后头结点可能就已经不再是之前的头结点了
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) { //头结点状态 Node.SIGNAL值为-1, 表示该节点处于等待唤醒状态
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) // 将等待唤醒的节点状态设置为0失败, 失败重试
continue; // loop to recheck cases
unparkSuccessor(h); // 唤醒下一个后继节点
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) // 头结点状态为0, 将其设置为-3(PROPAGATE), 表示该节点线程处于课运行状态, 失败重试
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break; // 退出循环
}
}
// 唤醒下一个后继节点
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
// 从尾节点向前遍历, 找到最后一个不为null, 且状态小于等于0的节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread); // 唤醒
}
2.1.2 releaseShared(int arg)
// 尝试释放同步状态, 释放成功则执行doReleaseShared
// 失败则返回false
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
// 若head节点为等待唤醒状态, 则将其状态设置为0, 然后唤醒下一个后继节点, 返回
// 若head节点状态为0, 则将其状态设置为-3, 线程可运行状态, 返回
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
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) // loop if head changed
break;
}
}
2.3 排他式超时(纳秒为单位)获取同步状态
nanosTimeout小于1000纳秒采用自旋实现是因为时间非常短, 很难做到精确控制, 因此不会让其进入超时等待, 而是进入自旋状态;
// 超时获取同步状态, 单位为纳秒, 若超时时间小于等于spinForTimeoutThreshold(1000纳秒), 则会进入自旋而不是进入等待;
public final boolean tryAcquireNanos(long arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
private boolean doAcquireNanos(long 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) // 只有超时时间大于spinForTimeoutThreshold才会进行等待
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
参考