摘要:為什么叫重入鎖呢,我們把它拆開來看就明了了。釋放鎖,每次鎖持有者數量遞減,直到為止。
相信大家在工作或者面試過程中經常聽到重入鎖這個概念,或者與關鍵字 synchrozied 的對比,棧長面試了這么多人,80%的面試者都沒有答對或沒有答到點上,或者把雙重效驗鎖搞混了,哭笑不得。。
那么你對重入鎖了解有多少呢?今天,棧長幫大家撕開重入鎖的面紗,來見識下重入鎖的真實容顏。。
什么是重入鎖java.util.concurrent.locks.ReentrantLock
這個是 JDK @since 1.5 添加的一種顆粒度更小的鎖,它完全可以替代 synchronized 關鍵字來實現它的所有功能,而且 ReentrantLock 鎖的靈活度要遠遠大于 synchronized 關鍵字。
從類結構圖看出,ReentrantLock 實現了 Lock 接口,ReentrantLock 只是 Lock 接口的一個實現而已。
java.util.concurrent.locks.Lock
它們都是 java.util.concurrent 包里面的內容(俗稱 JUC、并發包),也都是 JDK 1.5 開始加入的。
為什么叫重入鎖呢?ReentrantLock,我們把它拆開來看就明了了。
Re-Entrant-Lock:即表示可重新反復進入的鎖,但僅限于當前線程;
public void m() { lock.lock(); lock.lock(); try { // ... method body } finally { lock.unlock() lock.unlock() } }
如示例代碼所示,當前線程可以反復加鎖,但也需要釋放同樣加鎖次數的鎖,即重入了多少次,就要釋放多少次,不然也會導入鎖不被釋放。
試想一下,如果不設計成可重入鎖,那自己如果反復給自己加鎖,不是會把自己加死鎖了嗎?所以,到現在,重入鎖的概念大概應該清楚了吧?
重入鎖最重要的幾個方法這幾個方法都是 Lock 接口中定義的:
1)lock()
獲取鎖,有以下三種情況:
鎖空閑:直接獲取鎖并返回,同時設置鎖持有者數量為:1;
當前線程持有鎖:直接獲取鎖并返回,同時鎖持有者數量遞增1;
其他線程持有鎖:當前線程會休眠等待,直至獲取鎖為止;
2)lockInterruptibly()
獲取鎖,邏輯和 lock() 方法一樣,但這個方法在獲取鎖過程中能響應中斷。
3)tryLock()
從關鍵字字面理解,這是在嘗試獲取鎖,獲取成功返回:true,獲取失敗返回:false, 這個方法不會等待,有以下三種情況:
鎖空閑:直接獲取鎖并返回:true,同時設置鎖持有者數量為:1;
當前線程持有鎖:直接獲取鎖并返回:true,同時鎖持有者數量遞增1;
其他線程持有鎖:獲取鎖失敗,返回:false;
4)tryLock(long timeout, TimeUnit unit)
邏輯和 tryLock() 差不多,只是這個方法是帶時間的。
5)unlock()
釋放鎖,每次鎖持有者數量遞減 1,直到 0 為止。所以,現在知道為什么 lock 多少次,就要對應 unlock 多少次了吧。
6)newCondition
返回一個這個鎖的 Condition 實例,可以實現 synchronized 關鍵字類似 wait/ notify 實現多線程通信的功能,不過這個比 wait/ notify 要更靈活,更強大!
重入鎖大概的用法class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }}
看見沒有,加鎖和釋放鎖都在方法里面進行,可以自由控制,比 synchronized 更靈活,更方便。但要注意的是,釋放鎖操作必須在 finally 里面,不然如果出現異常導致鎖不能被正常釋放,進而會卡死后續所有訪問該鎖的線程。
synchronized 是重入鎖嗎?那么問題來了,synchronized 是重入鎖嗎?
你可能會說不是,因為 ReentrantLock 既然是重入鎖,根據推理,相反,那 synchronized 肯定就不是重入鎖,那你就錯了。
答案是:yes,為什么?看下面的例子:
public synchronized void operation(){ add(); } public synchronized void add(){ }
operation 方法調用了 add 方法,兩個方法都是用 synchronized 修飾的,add() 方法可以成功獲取當前線程 operation() 方法已經獲取到的鎖,說明 synchronized 就是可重入鎖。
面試常問的Synchronized的幾種用法推薦看下這篇文章:Synchronized 有幾種用法?。
總結今天,重入鎖就大概寫到這里了,其實重入鎖就是一種顆粒度更小的鎖,控制更方便,更強大,棧長只是簡單介紹一下重入鎖的基本概念及用法,但遠不止這么簡單,還有很多,一篇也難也詳盡,夠寫好多篇了。
大家也可以關注微信公眾號:Java技術棧,棧長將繼續分享更多重入鎖的高級的概念及工作中的實戰用法,請關注后續文章,或者在公眾號后臺回復:多線程,棧長已經整理好了許多 Java 多線程系列文章,都是接地氣干貨。
覺得有用,轉發分享下朋友圈給更多的人看吧,另外,給個好看,謝謝老板~
關注Java技術棧微信公眾號,棧長將繼續分享 Java 干貨教程,公眾號第一時間推送,持續關注。在公眾號后臺回復:java,獲取棧長整理的更多的 Java 教程,都是實戰干貨,以下僅為部分預覽。
你真的搞懂 transient 關鍵字了嗎?
面試常考:Synchronized 有幾種用法?
Java 11 已發布,String 還能這樣玩!
Java 中的 String 真的是不可變嗎?
sleep( ) 和 wait( ) 的這 5 個區別
……
本文原創首發于微信公眾號:Java技術棧(id:javastack),轉載請原樣保留本信息。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75024.html
摘要:所謂的重入,就是當本線程想再次獲得鎖,不需要重新申請,它本身就已經鎖了,即重入該鎖。如果不為,則表示有線程已經占有了。總結回顧下要點是一個可重入的鎖被當前占用的線程重入。 上一章《AQS源碼閱讀》講了AQS框架,這次講講它的應用類(注意不是子類實現,待會細講)。ReentrantLock,顧名思義重入鎖,但什么是重入,這個鎖到底是怎樣的,我們來看看類的注解說明showImg(http:...
摘要:二什么是重入鎖可重入鎖,顧名思義,支持重新進入的鎖,其表示該鎖能支持一個線程對資源的重復加鎖。將由最近成功獲得鎖,并且還沒有釋放該鎖的線程所擁有。可以使用和方法來檢查此情況是否發生。 一、寫在前面 前幾篇我們具體的聊了AQS原理以及底層源碼的實現,具體參見 《J.U.C|一文搞懂AQS》《J.U.C|同步隊列(CLH)》《J.U.C|AQS獨占式源碼分析》《J.U.C|AQS共享式源...
摘要:本文旨在對鎖相關源碼本文中的源碼來自使用場景進行舉例,為讀者介紹主流鎖的知識點,以及不同的鎖的適用場景。中,關鍵字和的實現類都是悲觀鎖。自適應意味著自旋的時間次數不再固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。 前言 Java提供了種類豐富的鎖,每種鎖因其特性的不同,在適當的場景下能夠展現出非常高的效率。本文旨在對鎖相關源碼(本文中的源碼來自JDK 8)、使用場景...
摘要:自己實現在自己實現之前先搞清楚阻塞隊列的幾個特點基本隊列特性先進先出。消費隊列空時會阻塞直到寫入線程寫入了隊列數據后喚醒消費線程。最終的隊列大小為,可見線程也是安全的。 showImg(https://segmentfault.com/img/remote/1460000018811340); 前言 較長一段時間以來我都發現不少開發者對 jdk 中的 J.U.C(java.util.c...
摘要:所以通過設置一個適中的拉取注冊表以及發送心跳的頻率,保證大規模系統里對的請求壓力不會太大。在注冊表發生變更的時候會在內存中更新變更的注冊表數據,同時過期掉。上述就是架構中,作為微服務注冊中心可以承載大規模系統每天千萬級訪問量的原理。 歡迎關注微信公眾號:石杉的架構筆記 周一至周五早8點!精品技術文章準時送上!! 往期文章1.拜托!面試請不要再問我Spring Cloud底層原理! 目...
閱讀 1937·2021-11-23 09:51
閱讀 1250·2019-08-30 15:55
閱讀 1622·2019-08-30 15:44
閱讀 768·2019-08-30 14:11
閱讀 1150·2019-08-30 14:10
閱讀 921·2019-08-30 13:52
閱讀 2635·2019-08-30 12:50
閱讀 620·2019-08-29 15:04