前言java
相信學過java的人都知道 synchronized 這個關鍵詞,也知道它用於控制多線程對併發資源的安全訪問,興許,你還用過Lock相關的功能,但你可能歷來沒有想過java中的鎖底層的機制是怎麼實現的。若是真是這樣,並且你有興趣瞭解,今天我將帶領你輕鬆的學習下java中很是重要,也很是基礎的可重入鎖-ReentrantLock的實現機制。
聽故事把知識掌握了編程
在一個村子裏面,有一口井水,水質很是的好,村民們都想打井裏的水。這井只有一口,村裏的人那麼多,因此得出個打水的規則才行。村長絞盡腦汁,最終想出了一個比較合理的方案,我們來仔細的看看聰明的村長大人的智慧。安全
井邊安排一個看井人,維護打水的秩序。多線程
打水時,以家庭爲單位,哪一個家庭任何人先到井邊,就能夠先打水,並且若是一個家庭佔到了打水權,其家人這時候過來打水不用排隊。而那些沒有搶佔到打水權的人,一個一個挨着在井邊排成一隊,先到的排在前面。打水示意圖以下 :併發
是否是感受很和諧,若是打水的人打完了,他會跟看井人報告,看井人會讓第二我的接着打水。這樣你們總都可以打到水。是否是看起來挺公平的,先到的人先打水,固然不是絕對公平的,本身看看下面這個場景 :工具
看着,一個有娃的父親正在打水,他的娃也到井邊了,因此女憑父貴直接排到最前面打水,羨煞旁人了。
以上這個故事模型就是所謂的公平鎖模型,當一我的想到井邊打水,而如今打水的人又不是自家人,這時候就得乖乖在隊列後面排隊。學習
事情總不是那麼一路順風的,總會有些人想走捷徑,話說看井人年紀大了,有時候,眼力不是很好,這時候,人們開始打起了新主意。新來打水的人,他們看到有人排隊打水的時候,他們不會那麼乖巧的就排到最後面去排隊,反之,他們會看看如今有沒有人正在打水,若是有人在打水,沒輒了,只好排到隊列最後面,但若是這時候前面打水的人剛剛打完水,正在交接中,排在隊頭的人尚未完成交接工做,這時候,新來的人能夠嘗試搶打水權,若是搶到了,呵呵,其餘人也只能睜一隻眼閉一隻眼,由於你們都默認這個規則了。這就是所謂的非公平鎖模型。新來的人不必定總得乖乖排隊,這也就形成了原來隊列中排隊的人可能要等好久好久。線程
java可重入鎖-ReentrantLock實現細節3d
ReentrantLock支持兩種獲取鎖的方式,一種是公平模型,一種是非公平模型。在繼續以前,我們先把故事元素轉換爲程序元素。blog
我們先來講說公平鎖模型:
初始化時, state=0,表示無人搶佔了打水權。這時候,村民A來打水(A線程請求鎖),佔了打水權,把state+1,以下所示:
線程A取得了鎖,把 state原子性+1,這時候state被改成1,A線程繼續執行其餘任務,而後來了村民B也想打水(線程B請求鎖),線程B沒法獲取鎖,生成節點進行排隊,以下圖所示:
初始化的時候,會生成一個空的頭節點,而後纔是B線程節點,這時候,若是線程A又請求鎖,是否須要排隊?答案固然是否認的,不然就直接死鎖了。當A再次請求鎖,就至關因而打水期間,同一家人也來打水了,是有特權的,這時候的狀態以下圖所示:
到了這裏,相信你們應該明白了什麼是可重入鎖了吧。就是一個線程在獲取了鎖以後,再次去獲取了同一個鎖,這時候僅僅是把狀態值進行累加。若是線程A釋放了一次鎖,就成這樣了:
僅僅是把狀態值減了,只有線程A把此鎖所有釋放了,狀態值減到0了,其餘線程纔有機會獲取鎖。當A把鎖徹底釋放後,state恢復爲0,而後會通知隊列喚醒B線程節點,使B能夠再次競爭鎖。固然,若是B線程後面還有C線程,C線程繼續休眠,除非B執行完了,通知了C線程。注意,當一個線程節點被喚醒而後取得了鎖,對應節點會從隊列中刪除。
非公平鎖模型
若是你已經明白了前面講的公平鎖模型,那麼非公平鎖模型也就很是容易理解了。當線程A執行完以後,要喚醒線程B是須要時間的,並且線程B醒來後還要再次競爭鎖,因此若是在切換過程中,來了一個線程C,那麼線程C是有可能獲取到鎖的,若是C獲取到了鎖,B就只能繼續乖乖休眠了。這裏就再也不畫圖說明了。
其它知識點
java5中添加了一個併發包, java.util.concurrent,裏面提供了各類併發的工具類,經過此工具包,能夠在java當中實現功能很是強大的多線程併發操做。對於每一個java攻城獅,我以爲很是有必要了解這個包的功能。雖然作不到一步到位,但慢慢虛心學習,沉下心來,總能慢慢領悟到java多線程編程的精華。
結束語
可重入鎖的實現會涉及到CAS,AQS,java內存可見性(volatile)等知識,爲了不你們直接被代碼搞暈,故而想以最簡單的方式把可重入鎖進行抽象,講明白其中的實現原理,這樣看起源碼也有個借鑑的思路,但願本篇可以幫助到大家。 ---------------------