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會從列表尾部取元素婶恼。
EntryList(鎖候選者列表)
EntryList是一個雙向鏈表。當(dāng)EntryList為空畅涂,cxq不為空港华,Owener會在unlock時,將cxq中的數(shù)據(jù)移動到EntryList午衰。并指定EntryList列表頭的第一個線程為OnDeck線程立宜。
EntryList跟cxq的區(qū)別
在cxq中的隊列可以繼續(xù)自旋等待鎖冒萄,若達到自旋的閾值仍未獲取到鎖則會調(diào)用park方法掛起。而EntryList中的線程都是被掛起的線程赘理。
WaitList
WatiList是Owner線程地調(diào)用wait()方法后進入的線程宦言。進入WaitList中的線程在notify()/notifyAll()調(diào)用后會被加入到EntryList。
Owner
當(dāng)前鎖持有者商模。
OnDeckThread
可進行鎖競爭的線程奠旺。若一個線程被設(shè)置為OnDeck,則表明其可以進行tryLock操作施流,若獲取鎖成功响疚,則變?yōu)镺wner,否則仍將其回插到EntryList頭部。
OnDeckThread競爭鎖失敗的原因
cxq中的線程可以進行自旋競爭鎖瞪醋,所以O(shè)nDeckThread若碰上自旋線程就需要和他們競爭
recursions(重入計數(shù)器)
用來表示某個線程進入該鎖的次數(shù)忿晕。
執(zhí)行流程
獲取monitor
- 線程首先通過CAS嘗試將monitor的owner設(shè)置為自己。
- 若執(zhí)行成功银受,則判斷該線程是不是重入践盼。若是重入,則執(zhí)行recursions + 1,否則執(zhí)行recursions = 1宾巍。
- 若失敗咕幻,則將自己封裝為ObjectWaiter,并通過CAS加入到cxq中顶霞。
釋放monitor
- 判斷是否為重量級鎖肄程,是則繼續(xù)流程。
- recursions - 1
- 根據(jù)不同的策略設(shè)置一個OnDeckThread