一個小例子幫助理解(我們常用的synchronized也是可重入鎖)
話說從前有一個村子,在這個村子中有一口水井,家家戶戶都需要到這口井里打水喝。由於井水有限,大家只能依次打水。為了實現家家有水喝,戶戶有水用的目標,村長絞盡腦汁,最終想出了一個比較合理的方案。
首先,在水井邊上安排一個看井人,負責維持秩序。
然后,打水時,以家庭為單位,哪個家庭任何人先到井邊,就可以先打水,而且如果一個家庭占到了打水權,其家人這時候過來打水不用排隊。而那些沒有搶占到打水權的人,一個一個挨着在井邊排成一隊,先到的排在前面。
最后,打水的人打完水以后就告訴看井人,看井人就讓等待的隊伍中的最前面一個去打水。
這樣一來,大家都能打到水,也保證了相對的公平。這就是公平鎖的基本思路。
隨着時間的推移,村民發現每次去打水的時候都需要排隊,想着每次排隊都浪費時間,於是就把水桶放在井邊代替,自己則溜回家去了。這樣一搞,可把看井人累壞,經常往村民家里跑,讓他們來打水。於是聰明的看井人想出了一個對策,如果有人打完水后,剛好又有其它人來打水,就直接讓這個新來的人上去打水,不用到隊伍末尾去排隊等候。
這種方式雖然看上去不公平,但是他節省了資源,提高了打水的性能,這就是非公平鎖的基本思路。
打水的小故事在java中的應用
Java中可重入鎖-ReentrantLock基本上就是按照上面的思路來實現的,我們來對給他們做一個簡單的對比。
一次只有一個人能打水 鎖需要保證多線程的同步。
必須嚴格按照排隊順序打水 ReentrantLock提供的公平鎖功能。
來得早不如來得巧 ReentrantLock提供的非公平鎖功能。
有家人正在打水的時候就不需要排隊 ReentrantLock的可重入特性。
那么可重入鎖又是怎樣實現上面那些特性的呢?
java可重入鎖-ReentrantLock實現細節
首先我們從上面的故事入手,看看ReentrantLock中的各個角色都是怎么樣的。
打水權 volatile int state
打水者 線程、Thread
打水隊伍 雙向鏈表Node
獲取鎖的時候,公平鎖的整個工作流程就如下圖所示:
可重入公平鎖獲取流程
在獲取鎖的時候,如果當前線程之前已經獲取到了鎖,就會把state加1,在釋放鎖的時候會先減1,這樣就保證了同一個鎖可以被同一個線程獲取多次,而不會出現死鎖的情況。這就是ReentrantLock的可重入性。
對於非公平鎖而言,調用lock方法后,會先嘗試搶占鎖,在各種判斷的時候會先忽略等待隊列,如果鎖可用,就會直接搶占使用。
釋放鎖的時候,整個工作流程如下圖:
可重入鎖釋放過程
本文為轉載:https://baijiahao.baidu.com/s?id=1594800969528243663&wfr=spider&for=pc
參考:https://blog.csdn.net/yanyan19880509/article/details/52345422