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

相信你們在工做或者面試過程當中常常聽到重入鎖這個概念,或者與關鍵字 synchrozied 的對比,棧長面試了這麼多人,80%的面試者都沒有答對或沒有答到點上,或者把雙重效驗鎖搞混了,啼笑皆非。。java

那麼你對重入鎖瞭解有多少呢?今天,棧長幫你們撕開重入鎖的面紗,來見識下重入鎖的真實容顏。。面試

什麼是重入鎖

java.util.concurrent.locks.ReentrantLock微信

這個是 JDK @since 1.5 添加的一種顆粒度更小的鎖,它徹底能夠替代 synchronized 關鍵字來實現它的全部功能,並且 ReentrantLock 鎖的靈活度要遠遠大於 synchronized 關鍵字。多線程

從類結構圖看出,ReentrantLock 實現了 Lock 接口,ReentrantLock 只是 Lock 接口的一個實現而已。併發

java.util.concurrent.locks.Lock.net

它們都是 java.util.concurrent 包裏面的內容(俗稱 JUC、併發包),也都是 JDK 1.5 開始加入的。線程

爲何叫重入鎖呢?

ReentrantLock,咱們把它拆開來看就明瞭了。設計

Re-Entrant-Lock:即表示可從新反覆進入的鎖,但僅限於當前線程;code

public void m() {

    lock.lock();

    lock.lock();

    try {

      // ... method body

    } finally {

      lock.unlock()

      lock.unlock()

    }

}

如示例代碼所示,當前線程能夠反覆加鎖,但也須要釋放一樣加鎖次數的鎖,即重入了多少次,就要釋放多少次,否則也會導入鎖不被釋放。blog

試想一下,若是不設計成可重入鎖,那本身若是反覆給本身加鎖,不是會把本身加死鎖了嗎?因此,到如今,重入鎖的概念大概應該清楚了吧?

重入鎖最重要的幾個方法

這幾個方法都是 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),轉載請原樣保留本信息。

相關文章
相關標籤/搜索