public void lock()
這是lock的原始碼,呼叫的其實是sync這個物件的lock函式,而sync是reentrantlock內部類sync的乙個物件例項,他有兩種實現nonfairsync(非公平鎖)和fairsync(公平鎖)
先看公平鎖的lock函式
final void lock()
只有一行**,呼叫的是aqs的acquire函式
public final void acquire(int arg)
按流程,先進入tryacquire
protected final boolean tryacquire(int acquires)
}//如果狀態不為0,則判斷是否為已經獲得鎖的物件進行重入鎖操作
else if (current == getexclusiveownerthread())
//獲取鎖失敗返回false
return false;
}
在獲取鎖的時候有兩步核心操作hasqueuedpredecessors(判斷當前等待獲取鎖的執行緒佇列是否為空)和compareandsetstate(將同步器狀態標記為accquires)
public final boolean hasqueuedpredecessors()
如果當前沒有執行緒在等待鎖則返回true,如果有則返回false
protected final boolean compareandsetstate(int expect, int update)
呼叫unsafe物件的cas函式為同步器的狀態進行修改,確保該操作為原子操作(同意時間若有多個執行緒進行該操作則只有乙個執行緒返回成功)
這兩步完成以後,就可以將當前執行緒標記為獨佔執行緒,該執行緒釋放鎖之前,再有執行緒來嘗試獲取鎖都會進入下一步acquirequeued(addwaiter(node.exclusive), arg)
先看addwaiter
private node addwaiter(node mode)
}enq(node);
return node;
}
將當前執行緒封裝成node物件,判斷tail物件是否為空,如果不為空則呼叫原子操作compareandsettail,將該節點設為tail,如果該操作失敗了,則呼叫enq函式
private node enq(final node node) else }}
}
該函式為乙個死迴圈,如果沒有tail則新建head同時設定head為tail,然後一直迴圈到這個節點加入佇列為止,加入成功後再將該節點返回出來,進入下一步操作acquirequeued
final boolean acquirequeued(final node node, int arg)
if (shouldparkafte***iledacquire(p, node) &&
parkandcheckinterrupt())
interrupted = true;
}} finally
}
可以看到這個函式裡也有乙個死迴圈,然後有兩個關鍵函式shouldparkafte***iledacquire(獲取鎖失敗後是否應該掛起)和parkandcheckinterrupt(掛起並檢查中斷狀態)
先看parkandcheckinterrupt
private final boolean parkandcheckinterrupt()
掛起當前執行緒,並返回了執行緒中斷狀態
然後是shouldparkafte***iledacquire
private static boolean shouldparkafte***iledacquire(node pred, node node) while (pred.waitstatus > 0);
pred.next = node;
} else
return false;
}
非公平鎖的lock
final void lock()
可以看到他會先嘗試修改一下狀態,如果成功就直接設定當前執行緒為獨佔執行緒
他的acquire也跟公平鎖不同
protected final boolean tryacquire(int acquires)
final boolean nonfairtryacquire(int acquires)
}else if (current == getexclusiveownerthread())
return false;
}
對比公平鎖,非公平鎖少了hasqueuedpredecessors這乙個判斷,他在嘗試獲取鎖的時候不會判斷當前是否有執行緒處於等待狀態
public void unlock()
unlock呼叫的是同步器的release函式
public final boolean release(int arg)
return false;
}
先呼叫tryrelease函式,如果返回成功,則喚醒頭節點執行緒
protected final boolean tryrelease(int releases)
setstate(c);
return free;
}
將狀態值減去要釋放的值,結果為零且執行tryrelease這個函式的當前執行緒為同步器的獨佔執行緒則釋放成功,將獨佔執行緒置為null,狀態置為0
private void unparksuccessor(node node)
if (s != null)
locksupport.unpark(s.thread);
}
先找head節點的next節點,如果其為空或者waitstatus大於0則從tail節點開始往回遍歷,找到排在最起碼的waitstatus大於0的節點,呼叫locksupport.unpark喚醒該節點 ReentrantLock 原理分析
鎖是一段 當執行緒執行到這段 時執行緒阻塞 掛起 或者進入輪詢 使用方式 reentrantlock lock new reentrantlock 預設建立非公平鎖 lock.lock 鎖住的 邏輯 lock.unlock 執行到 lock 方法時做的事情 建立的非公平鎖 1 判斷當前執行緒能否獲取...
ReentrantLock實現原理分析
本文只對reentrantlock中獲取鎖和釋放鎖的方法進行分析,其它方法不做分析。final void lock protected final boolean tryacquire int acquires else if current getexclusiveownerthread retu...
ReentrantLock之AQS原理與原始碼詳解
abstractqueuedsynchronizer,抽象佇列同步器 給大家畫乙個圖先,看一下reentrantlock和aqs之間的關係。abstractqueuedsynchronizer為reentrantlock的靜態內部類 2 預設為非公平鎖 3 最終會呼叫abstractqueuedsy...