一個(gè)小例子幫助理解(我們常用的synchronized也是可重入鎖)
話說(shuō)從前有一個(gè)村子,在這個(gè)村子中有一口水井,家家戶戶都需要到這口井里打水喝。由于井水有限,大家只能依次打水。為了實(shí)現(xiàn)家家有水喝,戶戶有水用的目標(biāo),村長(zhǎng)絞盡腦汁,最終想出了一個(gè)比較合理的方案。
首先,在水井邊上安排一個(gè)看井人,負(fù)責(zé)維持秩序。
然后,打水時(shí),以家庭為單位,哪個(gè)家庭任何人先到井邊,就可以先打水,而且如果一個(gè)家庭占到了打水權(quán),其家人這時(shí)候過(guò)來(lái)打水不用排隊(duì)。而那些沒(méi)有搶占到打水權(quán)的人,一個(gè)一個(gè)挨著在井邊排成一隊(duì),先到的排在前面。
最后,打水的人打完水以后就告訴看井人,看井人就讓等待的隊(duì)伍中的最前面一個(gè)去打水。
這樣一來(lái),大家都能打到水,也保證了相對(duì)的公平。這就是公平鎖的基本思路。
隨著時(shí)間的推移,村民發(fā)現(xiàn)每次去打水的時(shí)候都需要排隊(duì),想著每次排隊(duì)都浪費(fèi)時(shí)間,于是就把水桶放在井邊代替,自己則溜回家去了。這樣一搞,可把看井人累壞,經(jīng)常往村民家里跑,讓他們來(lái)打水。于是聰明的看井人想出了一個(gè)對(duì)策,如果有人打完水后,剛好又有其它人來(lái)打水,就直接讓這個(gè)新來(lái)的人上去打水,不用到隊(duì)伍末尾去排隊(duì)等候。
這種方式雖然看上去不公平,但是他節(jié)省了資源,提高了打水的性能,這就是非公平鎖的基本思路。
打水的小故事在java中的應(yīng)用
Java中可重入鎖-ReentrantLock基本上就是按照上面的思路來(lái)實(shí)現(xiàn)的,我們來(lái)對(duì)給他們做一個(gè)簡(jiǎn)單的對(duì)比。
一次只有一個(gè)人能打水 鎖需要保證多線程的同步。
必須嚴(yán)格按照排隊(duì)順序打水 ReentrantLock提供的公平鎖功能。
來(lái)得早不如來(lái)得巧 ReentrantLock提供的非公平鎖功能。
有家人正在打水的時(shí)候就不需要排隊(duì) ReentrantLock的可重入特性。
那么可重入鎖又是怎樣實(shí)現(xiàn)上面那些特性的呢?
java可重入鎖-ReentrantLock實(shí)現(xiàn)細(xì)節(jié)
首先我們從上面的故事入手,看看ReentrantLock中的各個(gè)角色都是怎么樣的。
打水權(quán) volatile int state
打水者 線程、Thread
打水隊(duì)伍 雙向鏈表Node
獲取鎖的時(shí)候,公平鎖的整個(gè)工作流程就如下圖所示:

可重入公平鎖獲取流程
在獲取鎖的時(shí)候,如果當(dāng)前線程之前已經(jīng)獲取到了鎖,就會(huì)把state加1,在釋放鎖的時(shí)候會(huì)先減1,這樣就保證了同一個(gè)鎖可以被同一個(gè)線程獲取多次,而不會(huì)出現(xiàn)死鎖的情況。這就是ReentrantLock的可重入性。
對(duì)于非公平鎖而言,調(diào)用lock方法后,會(huì)先嘗試搶占鎖,在各種判斷的時(shí)候會(huì)先忽略等待隊(duì)列,如果鎖可用,就會(huì)直接搶占使用。
釋放鎖的時(shí)候,整個(gè)工作流程如下圖:

可重入鎖釋放過(guò)程
本文為轉(zhuǎn)載:https://baijiahao.baidu.com/s?id=1594800969528243663&wfr=spider&for=pc
參考:https://blog.csdn.net/yanyan19880509/article/details/52345422