public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
接下來依次來看這三個(gè)方法。
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 中,這里有個(gè) compareAndSetHead(new Node()) 方法,這里是 new 了一個(gè)節(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í)行到這一步,就會(huì)調(diào)用 park 方法,一直在等著。當(dāng)線程A釋放鎖了,就會(huì)調(diào)用 unpark 方法,線程B和線程C就有一個(gè)可以搶到鎖了。
5. unlock 方法:
當(dāng)線程A調(diào)用了 unlock 方法,實(shí)際上調(diào)用的是:
public void unlock() { sync.release(1); }
點(diǎn)進(jìn)去之后是這樣的:
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); returntrue; } returnfalse; }
再點(diǎn)進(jìn)去看 tryRelease(arg 方法:
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
回到上一層,此時(shí)的 head 是傀儡節(jié)點(diǎn),不為空,并且傀儡節(jié)點(diǎn)的 waitStatus 剛才改成了 -1,不等于 0,所以會(huì)調(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è)置為空,所以最終效果就是: