並發王者課-鉑金3:一勞永逸-如何理解鎖的多次可重入問題


歡迎來到《並發王者課》,本文是該系列文章中的第16篇

在前面的文章《鉑金1:探本溯源-為何說Lock接口是Java中鎖的基礎》中,我們提到了鎖的可重入問題,並作了簡單介紹。鑒於鎖的可重入是一個重要概念,所以本文把拿出來做一次單獨講解,以幫助你徹底理解它。

一、鎖的可重入所造成的問題

首先,我們通過一段示例代碼看鎖的可重入是如何導致問題發生,以理解它的重要性。

public class ReentrantWildArea {
    // 野區鎖定
    private boolean isAreaLocked = false;

    // 進入野區A
    public synchronized void enterAreaA() throws InterruptedException {
        isAreaLocked = true;
        System.out.println("已經進入野區A...");
        enterAreaB();
    }
    // 進入野區B
    public synchronized void enterAreaB() throws InterruptedException {
        while (isAreaLocked) {
            System.out.println("野區B方法進入等待中...");
            wait();
        }
        System.out.println("已經進入野區B...");
    }

    public synchronized void unlock() {
        isAreaLocked = false;
        notify();
    }
}

在上面這段代碼中,我們創建了一片野區,包含了野區A野區B。接着,我們再創建一個打野英雄鎧,讓他進去野區打野,看看會發生什么事情。

public static void main(String[] args) {
  // 打野英雄鎧進入野區
  Thread kaiThread = new Thread(() -> {
    ReentrantWildArea wildArea = new ReentrantWildArea();
    try {
      wildArea.enterAreaA();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  });
  kaiThread.start();
}

輸出結果如下:

已經進入野區A...
野區B方法進入等待中...

從結果中可以看到,雖然在同一塊野區,但是鎧只進入野區A,卻沒能進入野區B,被阻塞在半道上了。從代碼分析上看,野區的兩個方法都聲明了synchronized,但鎧在進入野區A之后,野區進行了鎖定isAreaLocked = true,導致鎧進入野區B時失敗。

這就是典型的鎖的可重入所造成的問題。在並發編程時,如果未能處理好這一問題,將會造成線程的無限阻塞,其后果和死鎖相當

二、理解鎖的可重入

所謂鎖的可重入,指的是鎖可以被線程 重復遞歸 調用,也可以理解為對同一把鎖的重復獲取。 如果未能處理好鎖的可重入問題,將會導致和死鎖類似的問題。

三、如何避免鎖的可重入問題

避免鎖的可重入問題,需要注意兩個方面:

  • 盡量避免編寫需要重入獲取鎖的代碼
  • 如果需要,使用可重入鎖

在Java中,synchronized是可以重入的,下面的這段代碼在調用時不會產生重入問題。

public class WildMonster {
    public synchronized void A() {
        B();
    }
    
    public synchronized void B() {
       doSomething...
    }
}

但是,基於Lock接口所實現的各種鎖並不總是支持可重入的。在前面的文章中,我們已經展示過不支持重入的Lock接口實現。在具體的場景中使用時,需要務必注意這點。如果需要可重入鎖,可以使用Java中的ReentrantLock類。

小結

在本文中,我們再次介紹了鎖的可重入問題,並介紹了其產生的原因及避免方式。Java中的synchronized關鍵字支持鎖的可重入,但是其他顯示鎖並非總是支持這一特性,在使用時需要注意。

此外,需要注意的是,鎖的可重入對鎖的性能有一定的影響,而且實現起來更為復雜。所以,我們不能說鎖的可重入與不可重入哪個好,這要取決於具體的問題

正文到此結束,恭喜你又上了一顆星✨

夫子的試煉

  • 查看ReentrantLock源碼,了解其支持可重入的原理。

延伸閱讀與參考資料

關於作者

關注公眾號【庸人技術笑談】,獲取及時文章更新。記錄平凡人的技術故事,分享有品質(盡量)的技術文章,偶爾也聊聊生活和理想。不販賣焦慮,不做標題黨。

如果本文對你有幫助,歡迎點贊關注監督,我們一起從青銅到王者


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM