public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
接下来依次来看这三个方法。
2. tryAcquire(arg) 方法:
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
再点进去看 nonfairTryAcquire(acquires) :
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); returntrue; } } elseif (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); returntrue; } returnfalse; }
private Node enq(final Node node) { for (;;) { 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; } } } }
for (; ;) 其实就是相当于 while(true),进行自旋。当前的 tail 是 null ,所以进入 if 中,这里有个 compareAndSetHead(new Node()) 方法,这里是 new 了一个节点,姑且叫它傀儡节点,将它设置为头结点,如果 new 成功了,尾结点也指向它。效果如下图:
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ returntrue; if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. */ do { 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. */ compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
shouldParkAfterFailedAcquire(p, node) 方法返回了 false,因为自旋,所以又回到 final Node p = node.predecessor(); 这一行。此时 p 节点还是傀儡节点,再去尝试获取锁,如果线程A还是释放,又获取失败了,就会再次执行 shouldParkAfterFailedAcquire(p, node) 方法。
回到上一层,此时的 head 是傀儡节点,不为空,并且傀儡节点的 waitStatus 刚才改成了 -1,不等于 0,所以会调用 unparkSuccessor(h); 方法:
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; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); }