
// 伪代码
final boolean acquireQueued(final Node node, int arg) {
for (;;) {
// -------获取同步状态失败-------
// 获取失败后是否进入wait
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
}
/**
* 当获取同步状态失败后是否进入park状态
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
// 前驱节点为唤醒状态,返回true【后面代码暂时可以忽略】
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;
}
独占模式获取同步状态总结

2.2 释放同步状态
当线程执行完相应逻辑后,需要释放同步状态,使后继节点有机会同步状态(让出资源,让排队的线程使用)。这时就需要调用release(int arg)方法。调用该方法后,会唤醒后继节点。
释放同步状态,唤醒后继节点

/**
* 释放同步状态
*/
public final boolean release(int arg) {
// 1. 尝试释放同步状态
if (tryRelease(arg)) {
Node h = head;
// 释放成功后,执行unpark,既唤醒操作(暂时可忽略waitStatus,涉及到条件队列)
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
/**
* 尝试释放同步状态,既将同步状态减去指定的值
* 如果state = 0,表示当前线程 获取次数 = 释放次数,既释放成功,此时将持有同步状态线程标志为null
*/
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 状态码=0,表示释放成功了
if (c == 0) {
free = true;
// 独占标志设置为null
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
/**
* 唤醒后继节点操作
*/
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);
}
后继节点获取同步状态成功,头节点出队。需要注意的事,出队操作是间接的,有节点获取到同步状态时,会将当前节点设置为head,而原本的head设置为null。

/**
* 同步队列中节点,尝试获取同步状态(伪代码)
* 获取成功后,当前节点设置为头节点,头节点设置为null,既头节点出队
*/
final boolean acquireQueued(final Node node, int arg) {
try {
// 自旋(死循环)
for (;;) {
if (p == head && tryAcquire(arg)) {
// a. 操作:当前节点设置为头节点,当前节点的前驱节点设置为null
setHead(node);
// b. 原始的head的next设置为null,此时原始的head已经被移出队列
p.next = null; // help GC
failed = false;
return interrupted;
}
}
}
}
/**
* a.当前节点设置为头节点,当前节点的前驱节点设置为null
*/
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
2.3 其他竞争情况
当同步队列中头节点唤醒后继节点时,此时可能有其他线程尝试获取同步状态。

假设获取成功,将会被设置为头节点。