1. 程式人生 > >ReentrantLock實現原理及原始碼分析

ReentrantLock實現原理及原始碼分析

       ReentrantLock實現原理及原始碼分析

       ReentrantLock是Java併發包中提供的一個可重入的互斥鎖ReentrantLocksynchronized在基本用法,行為語義上都是類似的,同樣都具有可重入性。只不過相比原生的Synchronized,ReentrantLock增加了一些高階的擴充套件功能,比如它可以實現公平鎖,同時也可以繫結多個Conditon

可重入性/公平鎖/非公平鎖

可重入性

    所謂的可重入性,就是可以支援一個執行緒對鎖的重複獲取

,原生的synchronized就具有可重入性,一個用synchronized修飾的遞迴方法,當執行緒在執行期間,它是可以反覆獲取到鎖的,而不會出現自己把自己鎖死的情況。ReentrantLock也是如此,在呼叫lock()方法時,已經獲取到鎖的執行緒,能夠再次呼叫lock()方法獲取鎖而不被阻塞。那麼有可重入鎖,就有不可重入鎖,我們在之前文章中自定義的一個Mutex鎖就是個不可重入鎖,不過使用場景極少而已。

公平鎖/非公平鎖

    所謂公平鎖,顧名思義,意指鎖的獲取策略相對公平,當多個執行緒在獲取同一個鎖時,必須按照鎖的申請時間來依次獲得鎖,排排隊,不能插隊;非公平鎖則不同,當鎖被釋放時,等待中的執行緒均有機會獲得鎖。synchronized是非公平鎖,ReentrantLock預設也是非公平的,但是可以通過帶boolean引數的構造方法指定使用公平鎖,但非公平鎖的效能一般要優於公平鎖。

  synchronized是Java原生的互斥同步鎖,使用方便,對於synchronized修飾的方法或同步塊,無需再顯式釋放鎖。synchronized底層是通過monitorenter和monitorexit兩個位元組碼指令來實現加鎖解鎖操作的。而ReentrantLock做為API層面的互斥鎖,需要顯式地去加鎖解鎖。

class X {
    private final ReentrantLock lock = new ReentrantLock();
    // ...
 
    public void m() {
      lock.lock();  // 加鎖
      try {
        // ... 函式主題
      } finally {
        lock.unlock() //解鎖
      }
    }
  }

 ReentrantLock是基於AQS的,AQS是Java併發包中眾多同步元件的構建基礎,它通過一個int型別的狀態變數state和一個FIFO佇列來完成共享資源的獲取,執行緒的排隊等待等。AQS是個底層框架,採用模板方法模式,它定義了通用的較為複雜的邏輯骨架,比如執行緒的排隊,阻塞,喚醒等,將這些複雜但實質通用的部分抽取出來,這些都是需要構建同步元件的使用者無需關心的,使用者僅需重寫一些簡單的指定的方法即可(其實就是對於共享變數state的一些簡單的獲取釋放的操作)。

  上面簡單介紹了下AQS,詳細內容可參考本人的另一篇文章《Java併發包基石-AQS詳解》,此處就不再贅述了。先來看常用的幾個方法,我們從上往下推。

  無參構造器(預設為非公平鎖)

 

public ReentrantLock() {
        sync = new NonfairSync();//預設是公平的
    }

 sync是ReentrantLock內部實現的一個同步元件,它是Reentrantlock的一個靜態內部類,繼承於AQS,後面我們再分析。

  帶布林值的構造器(是否公平)

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();//fair為true,公平鎖;反之,非公平鎖
    }

看到了吧,此處可以指定是否採用公平鎖,FailSync和NonFailSync亦為Reentrantlock的靜態內部類,都繼承於Sync

  再來看看幾個我們常用到的方法

  lock()

public void lock() {
        sync.lock();//代理到Sync的lock方法上
    }

Sync的lock方法是抽象的,實際的lock會代理到FairSync或是NonFairSync上(根據使用者的選擇來決定,公平鎖還是非公平鎖)

  lockInterruptibly()

public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);//代理到sync的相應方法上,同lock方法的區別是此方法響應中斷
    }

此方法響應中斷,當執行緒在阻塞中的時候,若被中斷,會丟擲InterruptedException異常 

  tryLock()

public boolean tryLock() {
        return sync.nonfairTryAcquire(1);//代理到sync的相應方法上
    }

tryLock,嘗試獲取鎖,成功則直接返回true,不成功也不耽擱時間,立即返回false。

  unlock()

public void unlock() {
        sync.release(1);//釋放鎖
    }

釋放鎖,呼叫sync的release方法,其實是AQS的release邏輯。

   newCondition()

  獲取一個conditon,ReentrantLock支援多個Condition

public Condition newCondition() {
        return sync.newCondition();
    }

小結

  其實從上面這寫方法的介紹,我們都能大概梳理出ReentrantLock的處理邏輯,其內部定義了三個重要的靜態內部類,Sync,NonFairSync,FairSync。Sync作為ReentrantLock中公用的同步元件,繼承了AQS(要利用AQS複雜的頂層邏輯嘛,執行緒排隊,阻塞,喚醒等等);NonFairSync和FairSync則都繼承Sync,呼叫Sync的公用邏輯,然後再在各自內部完成自己特定的邏輯(公平或非公平)。

 

https://www.cnblogs.com/chengxiao/p/7255941.html