您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Java鎖中的重入鎖該怎么理解,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
在講重入鎖之前,我們先看一段代碼
上述代碼想要實現的效果,就是使用兩個線程對i分別進行累加一百萬次,最終希望i的值是二百萬,如果按照上述代碼運行程序,你會發現i的值在絕大多數情況下都不能達到200萬,原因就是多線程的數據同步問題。
為了解決上述問題,我們自然而然想到synchronized關鍵字,通過對程序進行簡單改造,如下圖,紅框中的部分就是程序變動的部分:
在此處synchronized關鍵字的作用就是,當每個線程試圖對i進行++操作時,必須要先獲取o對象,一個o對象在同一時刻只能被一個線程所持有,其他線程必須要等待持有o對象的線程進行i++操作并且釋放o對象之后去試圖獲取o對象,如果獲取成功線程繼續執行,如果獲取失敗,線程繼續等待。通過synchronized關鍵字會使原本并行化的操作變成順序執行,也就是說同一時刻,只會有一個線程對i進行++,因此i最終的值必定會是200萬。
通過synchronized關鍵字可以實現多線程之間的同步控制,除了上述方法,Java為我們提供了很多并發控制的工具類,今天主要講的就是Java中的重入鎖ReentrantLock,效果基本等同于synchronized關鍵字。
使用重入鎖必須獲取一個重入鎖對象,通過new一個ReentrantLock即可獲得一個重入鎖對象。
使用重入鎖必須明確指定加鎖和解鎖操作,增強程序的可讀性。
同一把重入鎖只能在同一時刻只能被同一個線程鎖持有,也就是說,當線程1通過lock方法獲取鎖成功之后,其他線程如果想要獲得鎖必須等待線程1通過unlock方法釋放鎖之后才能獲取成功。
重入鎖支持多次加鎖和多次解鎖操作,但是加鎖和解鎖的次數必須保持一致,如果一個線程的加鎖次數大于解鎖次數,會使得當前線程一直占有這把重入鎖,其他線程永遠無法獲取鎖,從而產生饑餓現象,相反如果解鎖的次數大于加鎖次數,程序則會拋出IllegalMonitorStateException異常。
重入鎖提供中斷響應,就是在等待鎖的過程中可以取消對鎖的請求。
通過圖片上的代碼,很輕松的就構造了一個死鎖現象,當lock值是1,線程會先試圖獲取重入鎖lock1,500ms之后再試圖獲取重入鎖lock2,相反如果lock值不是1,線程會先試圖獲取重入鎖lock2,500ms之后在試圖獲取重入鎖lock1,此時,我在主函數中新開兩個線程,設置lock的值一個為1,另一個為2;
此時運行程序,你會發現程序永遠不會結束,原因就是兩個線程之間形成了死鎖現象。
細心的讀者或許已經發現,我在獲取重入鎖的時候不是使用lock()方法,而是使用的lockInterruptibly()方法,通過方法名稱也可以看出,lockInterruptibly()方法是支持中斷響應的。
下面我會在主線程通過t2.interrupt()中斷thread-2線程,這樣重入鎖2就會被釋放,從而使得thread-1可以正確執行完畢,但是thread-2只是被中斷,無法正確執行完畢,只會執行finally塊中的方法,最終程序的輸出結果如下圖:
除了通過中斷線程我們還可以通過鎖申請等待限時來避免死鎖和饑餓現象,所謂的鎖申請等待限時指的是申請鎖時指定一個最大等待時間,如果超過了等待時間還沒獲得鎖,線程就不再進行等待并且繼續執行。
想要實現上述效果只需要在獲取鎖時使用tryLock方法來獲取鎖就可以,此方法會有一個boolean返回值,如果獲取鎖成功,返回值為true,如果失敗,返回值即為false。該方法有兩個重載方法,如下圖:
上述的實現方式都是非公平鎖,所謂的非公平就是,線程獲取鎖的成功率是隨機的,有些鎖可能會一直成功獲取鎖,而有些線程會一直獲取不到鎖,而那些獲取不到鎖的線程就會一直處于等待狀態,從而產生饑餓現象。
為了解決上述問題,重入鎖支持多個線程之間以一種公平的方式來競爭獲取鎖,通俗一點講比如有兩個線程,兩個線程試圖獲取同一把鎖,假如說第一次成功獲取鎖的是線程1,那么下次成功獲取鎖的必定是線程2而不是線程1。
公平重入鎖的實現只需要在獲取重入鎖時,構造參數中指定true。
上述代碼通過主線程中新開兩個線程,每個線程所做的事就是循環的獲取fairLock這把重入鎖,由于fairLock是一把公平的重入鎖,因此t1和t2兩個線程會交替獲得鎖,程序運行效果圖如下圖:
雖然公平的重入鎖可以避免死鎖的現象,但因內部必須要維護一個有序的線程隊列,所以公平鎖的實現成本較高,性能相對低下。
關于Java鎖中的重入鎖該怎么理解就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。