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 了一個節(jié)點,姑且叫它傀儡節(jié)點,將它設置為頭結點,如果 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 節(jié)點還是傀儡節(jié)點,再去嘗試獲取鎖,如果線程A還是釋放,又獲取失敗了,就會再次執(zhí)行 shouldParkAfterFailedAcquire(p, node) 方法。
回到上一層,此時的 head 是傀儡節(jié)點,不為空,并且傀儡節(jié)點的 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); }