Java中的重量級鎖是通過ObjectMonitor實現(xiàn)的。接下來簡單分析下ObjectMonitor的實現(xiàn)邏輯。
Objectmonitor中的關(guān)鍵詞
- EntryList
- WaitList
- cxq(ContentionList)
- Owner
- OnDeckThread
- recursions
cxq(競爭列表)
cxq是一個單向鏈表。被掛起線程等待重新競爭鎖的鏈表, monitor 通過CAS將包裝成ObjectWaiter寫入到列表的頭部。為了避免插入和取出元素的競爭,所以O(shè)wner會從列表尾部取元素。

重量級鎖3.jpg
EntryList(鎖候選者列表)
EntryList是一個雙向鏈表。當(dāng)EntryList為空,cxq不為空,Owener會在unlock時,將cxq中的數(shù)據(jù)移動到EntryList。并指定EntryList列表頭的第一個線程為OnDeck線程。
EntryList跟cxq的區(qū)別
在cxq中的隊列可以繼續(xù)自旋等待鎖,若達(dá)到自旋的閾值仍未獲取到鎖則會調(diào)用park方法掛起。而EntryList中的線程都是被掛起的線程。
WaitList
WatiList是Owner線程地調(diào)用wait()方法后進(jìn)入的線程。進(jìn)入WaitList中的線程在notify()/notifyAll()調(diào)用后會被加入到EntryList。
Owner
當(dāng)前鎖持有者。
OnDeckThread
可進(jìn)行鎖競爭的線程。若一個線程被設(shè)置為OnDeck,則表明其可以進(jìn)行tryLock操作,若獲取鎖成功,則變?yōu)镺wner,否則仍將其回插到EntryList頭部。
OnDeckThread競爭鎖失敗的原因
cxq中的線程可以進(jìn)行自旋競爭鎖,所以O(shè)nDeckThread若碰上自旋線程就需要和他們競爭
recursions(重入計數(shù)器)
用來表示某個線程進(jìn)入該鎖的次數(shù)。

重量級鎖2.jpg
執(zhí)行流程
獲取monitor
- 線程首先通過CAS嘗試將monitor的owner設(shè)置為自己。
- 若執(zhí)行成功,則判斷該線程是不是重入。若是重入,則執(zhí)行recursions + 1,否則執(zhí)行recursions = 1。
- 若失敗,則將自己封裝為ObjectWaiter,并通過CAS加入到cxq中。
釋放monitor
- 判斷是否為重量級鎖,是則繼續(xù)流程。
- recursions - 1
- 根據(jù)不同的策略設(shè)置一個OnDeckThread