Node节点
- 获取同步状态失败的线程,等待的状态,以及先驱和后继节点 将其加入同步队列,同事会阻塞当前线程,同步状态释放时, 会把首节点中的线程唤醒,使其再次获取同步状态
static final class Node {
/** 标志着一个节点是处在共享模式*/
static final Node SHARED = new Node();
/** 独占模式 */
static final Node EXCLUSIVE = null;
/** waitStatus 的值 标志着被取消 */
static final int CANCELLED = 1;
/** waitStatus 唤醒*/
static final int SIGNAL = -1;
/** waitStatus 表示线程正在等待条件 */
static final int CONDITION = -2;
/**
*无条件的将共享状态传播给下一个节点
*/
static final int PROPAGATE = -3;
/**
* Status field, taking on only the values:
* SIGNAL: -1 后继节点是阻塞的在阻塞队列中,所以当前节点当释放或者取消的时候必须唤醒他的后继。
* CANCELLED: 1 这个在同步队列中等待的节点由于超时或者中断,必须从同步队列取消,节点从来不会离开这个状态,
尤其是,一个被取消的节点线程不会再阻塞
* CONDITION: -2 节点在等待队列中
* PROPAGATE: -3 下一次共享模式同步状态获取将会无条件传播下去
* 0: 初始化
*
*负数表示一个节点不需要唤醒,所以大部分代码不需要检查,只是标志
*/
volatile int waitStatus;
/**
当前节点检查waitStatus状态依赖他连接到先驱的节点。在进入同步队列时分配,
在移除队列的时候归零(为了GC),在取消一个先驱节点时,当发现一个没有取消的节点时,
会短路,这种情况总是存在的,因为头结点永远不会被取消:一个节点编程头结点只是作为成功获取的结果,
并且一个线程只有取消自己,不管其他的节点。
*/
volatile Node prev;
/**
连接到的后继的节点在当前节点或线程释放时释放,进入同步队列时分配,
在绕过被取消的先驱节点时调整,并且在出对时取消(for GC)。
enq不会分配先驱节点的next,
所以看到一个节点的next是null不代表那是队列的结尾,
如果一个节点的next是null,可以从tail向前双重确认。
如果一个节点状态设置为取消next将会指向自己
*/
volatile Node next;
/**
* The thread that enqueued this node. Initialized on
* construction and nulled out after use.
*/
volatile Thread thread;
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
共享资源state
/**
同步状态 代表争用的共享资源,不同的自定义同步器争用共享资源的方式也不一样,
自定义同步器在实现时只需要实现共享资源state的共享与释放的方式即可
*/
private volatile int state;
protected final int getState() {
return state;
}
protected final void setState(int newState) {
state = newState;
}
enq将node插入队列
/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/
private Node enq(final Node node) {
for (;;) {//通过死循环CAS将节点正确加入queue中
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
/**
*将当前线程新建一个节点并入队
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 快速入队,如果失败就进入enq循环入队
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
shouldParkAfterFailedAcquire:检查并更新一个节点获取锁失败
如果这个线程应该被阻塞就返回true,这个在循环获取锁的代码中是主要的信号控制
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//前驱节点是signal,那么可以安全park
return true;
if (ws > 0) {
//前驱节点被cancel,那就跳过前驱节点,向前查找直到有前驱节点的ws小于0
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*ws必须是0或者是PROPAGATION,表明我们需要一个唤醒后继的信号,
但是不能阻塞,调用者需要重新确认他是否在阻塞前不能获取锁
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
//这里返回false让它再次确认ws是否cas设置为signal
return false;
}
//中断当前线程
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
* Convenience method to park and then check if interrupted
*
* @return {@code true} if interrupted
*/
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
使用addWaiter入队之后,就用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)) {//node的前驱节点是head,并且获取到锁,就设置node为头节点
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//如node应该park并且已中断,那么node就被挂起,直到被唤醒,
//就继续获取锁,直到获取到锁才会返回
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())
<B>throw new InterruptedException();</B>
}
} finally {
if (failed)
cancelAcquire(node);
}
}
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);//负数说明获取锁失败,0说明获取成功,但是后面节点不能再是共享模式
//大于0说明队列中的后继节点还可以继续使用共享模式
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);
}
}