-
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 (;😉 {
Node t = tail;
if (t == null) { // Must initialize @1
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
使用自旋来加入,众所周知,CLH算法,需要初始化一个假的 head 节点,也就是 head 节点并不代表一个等待获取锁的对象,AbstractQueuedSynchronzier 选择初始化 head,tail 的时机为第一次产生锁争用的时候。@1处为初始化head,tail,设置成功后,初始化后,再将新添加的节点放入到队列的尾部,然后该方法会返回原先的尾节点。addWaiter方法执行后,继续回到acquire(args)方法处:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
接下来,查看 acquireQueued 方法,addWaiter 方法返回的是代表当前线程的 Node 节点。
/**
-
Acquires in exclusive uninterruptible mode for thread already in
-
queue. Used by condition wait methods as well as acquire.
-
@param node the node
-
@param arg the acquire argument
-
@return {@code true} if interrupted while waiting
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;😉 {
final Node p = node.predecessor(); // @1
if (p == head && tryAcquire(arg)) { // @2
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt() ) //@3
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
首先@1,获取该节点的 node 的上一个节点。
@2如果node的前节点是head,因为head初始化时,都是假节点,不代表有线程拥有锁,所以,再次尝试获取锁,如果获取锁,则将锁的 head 设置为当前获取锁的线程的 Node,然后返回 false。返回 false, 则代表 if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 的结果为 false,直接返回,并不需要设置中断标记。如果当前节点不是head的话,则说明该锁被别的线程占用了,那就需要等待其他线程释放该锁,具体,我们看一下shouldParkAfterFailedAcquire,为了更好的理解 shouldParkAfterFailedAcquire, 我们先看一下parkAndCheckInterrupt 方法。
/**
-
Convenience method to park and then check if interrupted
-
阻塞该线程,然等待唤醒后,会返回 当前线程的中断位;
-
@return {@code true} if interrupted
*/
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
/**
-
Checks and updates status for a node that failed to acquire.
-
Returns true if thread should block. This is the main signal
-
control in all acquire loops. Requires that pred == node.prev
-
@param pred node’s predecessor holding status
-
@param node the node
-
@return {@code true} if thread should block
该方法,如果返回true,则代表该线程将被阻塞。
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; // @1
if (ws == Node.SIGNAL) // @2
/*
-
This node has already set status asking a