鎖機制(四)
本小節介紹鎖釋放Lock.unlock()。
Release/TryRelease
unlock操作實際上就調用了AQS的release操作,釋放持有的鎖。
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
前面提到過tryRelease(arg)操作,此操作裏面總是嘗試去釋放鎖,如果成功,說明鎖確實被當前線程持有,那麽就看AQS隊列中的頭結點是否為空並且能否被喚醒,如果可以的話就喚醒繼任節點(下一個非CANCELLED節點,下面會具體分析)。
對獨占鎖,java.util.concurrent.locks.ReentrantLock.Sync.tryRelease(int) 釋放鎖的過程。
protected final boolean tryRelease(int releases) { int c = getState() - releases;//將AQS狀態位減少要釋放的次數(對於獨占鎖而言總是1if (Thread.currentThread() != getExclusiveOwnerThread())//判斷持有鎖的線程是否是當前線程 throw new IllegalMonitorStateException();//如果不是就拋出IllegalMonitorStateExeception() boolean free = false; if (c == 0) { //如果剩余的狀態位0(也就是沒有線程持有鎖) free = true;// setExclusiveOwnerThread(null);//當前線程是最後一個持有鎖的線程,清空AQS持有鎖的獨占線程 } setState(c);//將剩余的狀態位寫回AQS,如果沒有線程持有鎖就返回true,否則就是falsereturn free; }
參考上一節的分析就可以知道,這裏c==0決定了是否完全釋放了鎖。由於ReentrantLock是可重入鎖,因此同一個線程可能多重持有鎖,那麽當且僅當最後一個持有鎖的線程釋放鎖是才能將AQS中持有鎖的獨占線程清空,這樣接下來的操作才需要喚醒下一個需要鎖的AQS節點(Node),否則就只是減少鎖持有的計數器,並不能改變其他操作。
當tryRelease操作成功後(也就是完全釋放了鎖),release操作才能檢查是否需要喚醒下一個繼任節點。這裏的前提是AQS隊列的頭結點需要鎖(waitStatus!=0),如果頭結點需要鎖,就開始檢測下一個繼任節點是否需要鎖操作。
在上一節中說道acquireQueued操作完成後(拿到了鎖),會將當前持有鎖的節點設為頭結點,所以一旦頭結點釋放鎖,那麽就需要尋找頭結點的下一個需要鎖的繼任節點,並喚醒它。
private void unparkSuccessor(Node node) { //此時node是需要是需要釋放鎖的頭結點 //清空頭結點的waitStatus,也就是不再需要鎖了 compareAndSetWaitStatus(node, Node.SIGNAL, 0); //從頭結點的下一個節點開始尋找繼任節點,當且僅當繼任節點的waitStatus<=0才是有效繼任節點,否則將這些waitStatus>0(也就是CANCELLED的節點)從AQS隊列中剔除 //這裏並沒有從head->tail開始尋找,而是從tail->head尋找最後一個有效節點。 //解釋在這裏 http://www.blogjava.net/xylz/archive/2010/07/08/325540.html#377512 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); }
公平鎖和非公平鎖只是在獲取鎖的時候有差別,其它都是一樣的。
在上面非公平鎖的代碼中總是優先嘗試當前是否有線程持有鎖,一旦沒有任何線程持有鎖,那麽非公平鎖就霸道的嘗試將鎖“占為己有”。如果在搶占鎖的時候失敗就和公平鎖一樣老老實實的去排隊。
也即是說公平鎖和非公平鎖只是在入AQS的CLH隊列之前有所差別,一旦進入了隊列,所有線程都是按照隊列中先來後到的順序請求鎖。
鎖機制(四)