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); }
再點(diǎn)進(jìn)去看 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 (; ;) 其實(shí)就是相當(dāng)于 while(true),進(jìn)行自旋,。當(dāng)前的 tail 是 null ,所以進(jìn)入 if 中,,這里有個 compareAndSetHead(new Node()) 方法,,這里是 new 了一個節(jié)點(diǎn),姑且叫它傀儡節(jié)點(diǎn),,將它設(shè)置為頭結(jié)點(diǎn),,如果 new 成功了,尾結(jié)點(diǎn)也指向它,。效果如下圖:
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; }
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
這里的 this 就是線程B,這里調(diào)用了 park 方法,,就讓線程B 在等著了,。線程C進(jìn)來也一樣,執(zhí)行到這一步,,就會調(diào)用 park 方法,,一直在等著。當(dāng)線程A釋放鎖了,,就會調(diào)用 unpark 方法,,線程B和線程C就有一個可以搶到鎖了。
回到上一層,此時的 head 是傀儡節(jié)點(diǎn),,不為空,,并且傀儡節(jié)點(diǎn)的 waitStatus 剛才改成了 -1,不等于 0,,所以會調(diào)用 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); }
這里的 node 就是線程B節(jié)點(diǎn),,將頭結(jié)點(diǎn)指向線程B節(jié)點(diǎn),將線程B節(jié)點(diǎn)的線程設(shè)置為空,,前驅(qū)設(shè)置為空,。外層再把傀儡節(jié)點(diǎn)的 next 指針設(shè)置為空,所以最終效果就是: