Java高級(jí)編程——Lock 鎖的高級(jí)用法

Java 5 中引入了新的鎖機(jī)制——java.util.concurrent.locks 中的顯式的互斥鎖:Lock 接口,

它提供了比?synchronized?更加廣泛的鎖定操作。 Lock 接口有 3 個(gè)實(shí)現(xiàn)它的類:ReentrantLock、ReetrantReadWriteLock.ReadLock 和 ReetrantReadWriteLock.WriteLock,即重入鎖、讀鎖和寫鎖。 lock 必須被顯式地創(chuàng)建、鎖定和釋放,為了可以使用更多的功能,一般用 ReentrantLock 為其實(shí)例化。為了保證鎖最終一定會(huì)被釋放(可能會(huì)有異常發(fā)生),要把互斥區(qū)放在 try 語(yǔ)句塊內(nèi),并在 finally 語(yǔ)句塊中釋放鎖,尤其當(dāng)有 return 語(yǔ)句時(shí),return 語(yǔ)句必須放在 try 字句中,以確保 unlock()不會(huì)過(guò)早發(fā)生,從而將數(shù)據(jù)暴露給第二個(gè)任務(wù)。因此,采用 lock 加鎖和釋放鎖的一般形式如下:

//默認(rèn)使用非公平鎖,如果要使用公平鎖,需要傳入?yún)?shù)trueLock lock = new ReentrantLock();lock.lock(); try { // 更新對(duì)象的狀態(tài) // 捕獲異常,必要時(shí)恢復(fù)到原來(lái)的不變約束 // 如果有return語(yǔ)句,放在這里 } finally { //鎖必須在finally塊中釋放lock.unlock();}

可重入鎖,也叫做遞歸鎖,指的是同一線程外層函數(shù)獲得鎖之后,內(nèi)層遞歸函數(shù)仍然有獲取該鎖的代碼,但不受影響。 在JAVA環(huán)境下?ReentrantLock?和?synchronized?都是可重入鎖。

ReentrantReadWriteLock

讀寫鎖:分為讀鎖和寫鎖,多個(gè)讀鎖不互斥,讀鎖與寫鎖互斥,這是由jvm自己控制的,你只要上好相應(yīng)的鎖即可。 如果你的代碼只讀數(shù)據(jù),可以很多人同時(shí)讀,但不能同時(shí)寫,那就上讀鎖;如果你的代碼修改數(shù)據(jù),只能有一個(gè)人在寫,且不能同時(shí)讀取,那就上寫鎖。 總之,讀的時(shí)候上讀鎖,寫的時(shí)候上寫鎖!

ReentrantReadWriteLock?會(huì)使用兩把鎖來(lái)解決問(wèn)題,一個(gè)讀鎖,一個(gè)寫鎖

線程進(jìn)入讀鎖的前提條件

沒(méi)有其他線程的寫鎖

沒(méi)有寫請(qǐng)求或者有寫請(qǐng)求,但調(diào)用線程和持有鎖的線程是同一個(gè)

線程進(jìn)入寫鎖的前提條件

沒(méi)有其他線程的讀鎖

沒(méi)有其他線程的寫鎖

StampedLock

StampedLock?是 java 8 在?java.util.concurrent.locks?新增的一個(gè)API。

ReentrantReadWriteLock?在沒(méi)有任何讀鎖和寫鎖時(shí),才可以取得寫入鎖,這可用于實(shí)現(xiàn)了悲觀讀取。 然而,如果讀取很多,寫入很少的情況下,使用?ReentrantReadWriteLock?可能會(huì)使寫入線程遭遇饑餓問(wèn)題,也就是寫入線程無(wú)法競(jìng)爭(zhēng)到鎖定而一直處于等待狀態(tài)。?StampedLock?有三種模式的鎖,用于控制讀取/寫入訪問(wèn),StampedLock 的狀態(tài)由版本和模式組成。 鎖獲取操作返回一個(gè)用于展示和訪問(wèn)鎖狀態(tài)的票據(jù)(stamp)變量,它用相應(yīng)的鎖狀態(tài)表示并控制訪問(wèn),數(shù)字0表示沒(méi)有寫鎖被授權(quán)訪問(wèn)。 在讀鎖上分為悲觀鎖和樂(lè)觀鎖,鎖釋放以及其他相關(guān)方法需要使用郵戳(stamps)變量作為參數(shù),如果他們和當(dāng)前鎖狀態(tài)不符則失敗,這三種模式為:

寫入:方法writeLock可能為了獲取獨(dú)占訪問(wèn)而阻塞當(dāng)前線程,返回一個(gè)stamp變量,能夠在unlockWrite方法中使用從而釋放鎖。也提供了tryWriteLock。 當(dāng)鎖被寫模式所占有,沒(méi)有讀或者樂(lè)觀的讀操作能夠成功。

讀?。悍椒╮eadLock可能為了獲取非獨(dú)占訪問(wèn)而阻塞當(dāng)前線程,返回一個(gè)stamp變量,能夠在unlockRead方法中用于釋放鎖。也提供了tryReadLock。

樂(lè)觀讀?。悍椒?tryOptimisticRead?返回一個(gè)非 0 郵戳變量,僅在當(dāng)前鎖沒(méi)有以寫入模式被持有。如果在獲得stamp變量之后沒(méi)有被寫模式持有,方法validate將返回true。 這種模式可以被看做一種弱版本的讀鎖,可以被一個(gè)寫入者在任何時(shí)間打斷。樂(lè)觀讀取模式僅用于短時(shí)間讀取操作時(shí)經(jīng)常能夠降低競(jìng)爭(zhēng)和提高吞吐量。

悲觀鎖(Pessimistic Lock),顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。 悲觀鎖:假定會(huì)發(fā)生并發(fā)沖突,屏蔽一切可能違反數(shù)據(jù)完整性的操作。 Java synchronized 就屬于悲觀鎖的一種實(shí)現(xiàn),每次線程要修改數(shù)據(jù)時(shí)都先獲得鎖,保證同一時(shí)刻只有一個(gè)線程能操作數(shù)據(jù),其他線程則會(huì)被block。

樂(lè)觀鎖(Optimistic Lock),顧名思義,就是很樂(lè)觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在提交更新的時(shí)候會(huì)判斷一下在此期間別人有沒(méi)有去更新這個(gè)數(shù)據(jù)。 樂(lè)觀鎖適用于讀多寫少的應(yīng)用場(chǎng)景,這樣可以提高吞吐量。 樂(lè)觀鎖:假設(shè)不會(huì)發(fā)生并發(fā)沖突,只在提交操作時(shí)檢查是否違反數(shù)據(jù)完整性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 所以做為用心真正修行的人,在生活中周圍的人可能看不大出你有任何的“異相”,而且別人越是看不出你在修行你的段位可能就...
    米妙和閱讀 555評(píng)論 0 1
  • 昨日有幸在襲人花店聽(tīng)聞師兄的師父講授正法,我也提了自己的疑惑,說(shuō)到工作中有小人,時(shí)常感到不安,心中有怒意,甚至有爭(zhēng)...
    何魏閱讀 218評(píng)論 0 1

友情鏈接更多精彩內(nèi)容