溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java鎖中的重入鎖該怎么理解

發(fā)布時間:2021-11-20 15:31:43 來源:億速云 閱讀:142 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細講解有關(guān)Java鎖中的重入鎖該怎么理解,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

在講重入鎖之前,我們先看一段代碼

Java鎖中的重入鎖該怎么理解

上述代碼想要實現(xiàn)的效果,就是使用兩個線程對i分別進行累加一百萬次,最終希望i的值是二百萬,如果按照上述代碼運行程序,你會發(fā)現(xiàn)i的值在絕大多數(shù)情況下都不能達到200萬,原因就是多線程的數(shù)據(jù)同步問題。

為了解決上述問題,我們自然而然想到synchronized關(guān)鍵字,通過對程序進行簡單改造,如下圖,紅框中的部分就是程序變動的部分:

Java鎖中的重入鎖該怎么理解

在此處synchronized關(guān)鍵字的作用就是,當每個線程試圖對i進行++操作時,必須要先獲取o對象,一個o對象在同一時刻只能被一個線程所持有,其他線程必須要等待持有o對象的線程進行i++操作并且釋放o對象之后去試圖獲取o對象,如果獲取成功線程繼續(xù)執(zhí)行,如果獲取失敗,線程繼續(xù)等待。通過synchronized關(guān)鍵字會使原本并行化的操作變成順序執(zhí)行,也就是說同一時刻,只會有一個線程對i進行++,因此i最終的值必定會是200萬。

通過synchronized關(guān)鍵字可以實現(xiàn)多線程之間的同步控制,除了上述方法,Java為我們提供了很多并發(fā)控制的工具類,今天主要講的就是Java中的重入鎖ReentrantLock,效果基本等同于synchronized關(guān)鍵字。

 使用重入鎖必須獲取一個重入鎖對象,通過new一個ReentrantLock即可獲得一個重入鎖對象。

Java鎖中的重入鎖該怎么理解

 使用重入鎖必須明確指定加鎖和解鎖操作,增強程序的可讀性。

Java鎖中的重入鎖該怎么理解

同一把重入鎖只能在同一時刻只能被同一個線程鎖持有,也就是說,當線程1通過lock方法獲取鎖成功之后,其他線程如果想要獲得鎖必須等待線程1通過unlock方法釋放鎖之后才能獲取成功。

重入鎖支持多次加鎖和多次解鎖操作,但是加鎖和解鎖的次數(shù)必須保持一致,如果一個線程的加鎖次數(shù)大于解鎖次數(shù),會使得當前線程一直占有這把重入鎖,其他線程永遠無法獲取鎖,從而產(chǎn)生饑餓現(xiàn)象,相反如果解鎖的次數(shù)大于加鎖次數(shù),程序則會拋出IllegalMonitorStateException異常。

重入鎖提供中斷響應,就是在等待鎖的過程中可以取消對鎖的請求。

Java鎖中的重入鎖該怎么理解

通過圖片上的代碼,很輕松的就構(gòu)造了一個死鎖現(xiàn)象,當lock值是1,線程會先試圖獲取重入鎖lock1,500ms之后再試圖獲取重入鎖lock2,相反如果lock值不是1,線程會先試圖獲取重入鎖lock2,500ms之后在試圖獲取重入鎖lock1,此時,我在主函數(shù)中新開兩個線程,設置lock的值一個為1,另一個為2;

Java鎖中的重入鎖該怎么理解

此時運行程序,你會發(fā)現(xiàn)程序永遠不會結(jié)束,原因就是兩個線程之間形成了死鎖現(xiàn)象。

細心的讀者或許已經(jīng)發(fā)現(xiàn),我在獲取重入鎖的時候不是使用lock()方法,而是使用的lockInterruptibly()方法,通過方法名稱也可以看出,lockInterruptibly()方法是支持中斷響應的。

下面我會在主線程通過t2.interrupt()中斷thread-2線程,這樣重入鎖2就會被釋放,從而使得thread-1可以正確執(zhí)行完畢,但是thread-2只是被中斷,無法正確執(zhí)行完畢,只會執(zhí)行finally塊中的方法,最終程序的輸出結(jié)果如下圖:

Java鎖中的重入鎖該怎么理解

除了通過中斷線程我們還可以通過鎖申請等待限時來避免死鎖和饑餓現(xiàn)象,所謂的鎖申請等待限時指的是申請鎖時指定一個最大等待時間,如果超過了等待時間還沒獲得鎖,線程就不再進行等待并且繼續(xù)執(zhí)行。

想要實現(xiàn)上述效果只需要在獲取鎖時使用tryLock方法來獲取鎖就可以,此方法會有一個boolean返回值,如果獲取鎖成功,返回值為true,如果失敗,返回值即為false。該方法有兩個重載方法,如下圖:

Java鎖中的重入鎖該怎么理解

上述的實現(xiàn)方式都是非公平鎖,所謂的非公平就是,線程獲取鎖的成功率是隨機的,有些鎖可能會一直成功獲取鎖,而有些線程會一直獲取不到鎖,而那些獲取不到鎖的線程就會一直處于等待狀態(tài),從而產(chǎn)生饑餓現(xiàn)象。

為了解決上述問題,重入鎖支持多個線程之間以一種公平的方式來競爭獲取鎖,通俗一點講比如有兩個線程,兩個線程試圖獲取同一把鎖,假如說第一次成功獲取鎖的是線程1,那么下次成功獲取鎖的必定是線程2而不是線程1。

公平重入鎖的實現(xiàn)只需要在獲取重入鎖時,構(gòu)造參數(shù)中指定true。

Java鎖中的重入鎖該怎么理解

Java鎖中的重入鎖該怎么理解

上述代碼通過主線程中新開兩個線程,每個線程所做的事就是循環(huán)的獲取fairLock這把重入鎖,由于fairLock是一把公平的重入鎖,因此t1和t2兩個線程會交替獲得鎖,程序運行效果圖如下圖:

Java鎖中的重入鎖該怎么理解

雖然公平的重入鎖可以避免死鎖的現(xiàn)象,但因內(nèi)部必須要維護一個有序的線程隊列,所以公平鎖的實現(xiàn)成本較高,性能相對低下。

關(guān)于Java鎖中的重入鎖該怎么理解就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI