天天看點

到底什麼是重入鎖,拜托,一次搞清楚!

到底什麼是重入鎖,拜托,一次搞清楚!

Java技術棧

www.javastack.cn

優秀的Java技術公衆号

相信大家在工作或者面試過程中經常聽到重入鎖這個概念,或者與關鍵字 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.lock();    lock.lock();    try {      // ... method body    } finally {      lock.unlock()      lock.unlock()    }}      

如示例代碼所示,目前線程可以反複加鎖,但也需要釋放同樣加鎖次數的鎖,即重入了多少次,就要釋放多少次,不然也會導入鎖不被釋放。

試想一下,如果不設計成可重入鎖,那自己如果反複給自己加鎖,不是會把自己加死鎖了嗎?是以,到現在,重入鎖的概念大概應該清楚了吧?

重入鎖最重要的幾個方法

這幾個方法都是 Lock 接口中定義的:

到底什麼是重入鎖,拜托,一次搞清楚!

1)lock()

擷取鎖,有以下三種情況:

2)lockInterruptibly()

擷取鎖,邏輯和 lock() 方法一樣,但這個方法在擷取鎖過程中能響應中斷。

3)tryLock()

從關鍵字字面了解,這是在嘗試擷取鎖,擷取成功傳回:true,擷取失敗傳回: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()    }  }}}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(){}    add();}public synchronized void add(){}      

operation 方法調用了 add 方法,兩個方法都是用 synchronized 修飾的,add()  方法可以成功擷取目前線程 operation() 方法已經擷取到的鎖,說明 synchronized 就是可重入鎖。

面試常問的Synchronized的幾種用法推薦看下這篇文章:Synchronized 有幾種用法?。

總結

今天,重入鎖就大概寫到這裡了,其實重入鎖就是一種顆粒度更小的鎖,控制更友善,更強大,棧長隻是簡單介紹一下重入鎖的基本概念及用法,但遠不止這麼簡單,還有很多,一篇也難也詳盡,夠寫好多篇了。

大家也可以關注微信公衆号:Java技術棧,棧長将繼續分享更多重入鎖的進階的概念及工作中的實戰用法,請關注後續文章,或者在公衆号背景回複:多線程,棧長已經整理好了許多 Java 多線程系列文章,都是接地氣幹貨。

覺得有用,轉發分享下朋友圈給更多的人看吧~