源碼分析
1.unlock()方法實際是調(diào)用父類AQS的release()方法
public void unlock() {
sync.release(1);
}
2.release()方法首先又調(diào)用了tryRelease(1)方法怖亭,這個方法依舊由AQS的子類Sync類來實現(xiàn),見2.1分析
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
2.1 tryRelease()方法主要是對鎖狀態(tài)值進(jìn)行還原,并且釋放占有鎖的線程位迂,并將解鎖的結(jié)果返回
protected final boolean tryRelease(int releases) {
//將鎖的狀態(tài)值-1
int c = getState() - releases;
//如果擁有鎖的線程不是現(xiàn)在的運行線程琅拌,則拋出異常拄轻,避免未lock情況下unlock
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
//鎖空閑標(biāo)識搅裙,默認(rèn)否
boolean free = false;
//如果鎖的狀態(tài)值恢復(fù)到0皱卓,則將鎖空閑標(biāo)識改為true总放,并將鎖的所屬線程設(shè)置為null
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
//將鎖的狀態(tài)值同步到AQS里
setState(c);
return free;
}
這里會有兩種情況
第一種情況不是重入鎖,釋放鎖后好爬,free狀態(tài)返回true局雄,再繼續(xù)后續(xù)的喚醒等待線程操作。
第二種情況如果是重入鎖釋放鎖存炮,則free狀態(tài)還是false炬搭,只是state的值遞減1,后面喚醒鎖的操作不會執(zhí)行
2.2 上面2.1分析的方法如果返回false則解鎖過程結(jié)束穆桂,如果返回true則繼續(xù)接第2步if方法體里代碼進(jìn)行喚醒等待線程
public final boolean release(int arg) {
if (tryRelease(arg)) {
//拿到頭節(jié)點
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
如果頭節(jié)點不是空宫盔,且頭節(jié)點的狀態(tài)不是0,執(zhí)行unparkSuccessor(h),入?yún)轭^節(jié)點享完,進(jìn)行喚醒操作;
private void unparkSuccessor(Node node) {
//頭節(jié)點狀態(tài)
int ws = node.waitStatus;
//如果頭節(jié)點的狀態(tài)是-1將狀態(tài)改為0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//頭節(jié)點的后繼節(jié)點
Node s = node.next;
//如果后繼節(jié)點是null灼芭,或者狀態(tài)大于等于0,說明后繼節(jié)點取消了般又,為無效節(jié)點
if (s == null || s.waitStatus > 0) {
s = null;
//從尾節(jié)點往前循環(huán)彼绷,找到符合狀態(tài)為小于等于0的節(jié)點,并賦給s
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//s不為null時茴迁,喚醒節(jié)點里的線程
//喚醒的線程會從掛起的地方開始執(zhí)行寄悯,也就是繼上一篇文章《ReentrantLock源碼解析(加鎖)》第5.2.2節(jié)第5行繼續(xù)執(zhí)行。
if (s != null)
LockSupport.unpark(s.thread);
}
這個方法做了幾步操作有健壯性的考慮堕义,
1.將頭節(jié)點的狀態(tài)改為0猜旬,避免重復(fù)循環(huán)
2.取到頭節(jié)點的后繼節(jié)點
3.校驗后繼節(jié)點的狀態(tài)是否可以被喚醒,如果后繼節(jié)點是空的倦卖,或者狀態(tài)大于0(線程被取消或者中斷)洒擦,則從尾節(jié)點開始循環(huán)找出最前面(FIFO隊列特點)可以被喚醒的線程。
4.喚醒上面2怕膛,3最終確定的等待線程
----------------- 文章如有問題熟嫩,請下方回復(fù)指出,感謝查閱?? -----------------