Java併發編程解析 | 基於JDK源碼解析Java領域中ReentrantLock鎖的設計思想與實現原理 (一)

蒼穹之邊,浩瀚之摯,眰恦之美; 悟心悟性,善始善終,惟善惟道! —— 朝槿《朝槿兮年說》


寫在開頭

在併發編程領域,有兩大核心問題:一個是互斥,即同一時刻只允許一個線程訪問共享資源;另一個是同步,即線程之間如何通信、協作。
主要原因是,對於多線程實現實現併發,一直以來,多線程都存在2個問題:

  • 線程之間內存共享,需要通過加鎖進行控制,但是加鎖會導致性能下降,同時複雜的加鎖機制也會增加編程編碼難度
  • 過多線程造成線程之間的上下文切換,導致效率低下

因此,在併發編程領域中,一直有一個很重要的設計原則: “ 不要通過內存共享來實現通信,而應該通過通信來實現內存共享。”
簡單來說,就是儘可能通過消息通信,而不是內存共享來實現進程或者線程之間的同步。

關健術語


本文用到的一些關鍵詞語以及常用術語,主要如下:

  • 併發(Concurrent): 在操作系統中,是指一個時間段中有幾個程序都處於已啓動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行。
  • 並行(Parallel): 當系統有一個以上CPU時,當一個CPU執行一個進程時,另一個CPU可以執行另一個進程,兩個進程互不搶佔CPU資源,可以同時進行。
  • 信號量(Semaphore):  是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被併發調用,也是作系統用來解決併發中的互斥和同步問題的一種方法。
  • 信號量機制(Semaphores): 用來解決同步/互斥的問題的,它是1965年,荷蘭學者 Dijkstra提出了一種卓有成效的實現進程互斥與同步的方法。
  • 管程(Monitor) :  一般是指管理共享變量以及對共享變量的操作過程,讓它們支持併發的一種機制。
  • 互斥(Mutual Exclusion):一個公共資源同一時刻只能被一個進程或線程使用,多個進程或線程不能同時使用公共資源。即就是同一時刻只允許一個線程訪問共享資源的問題。
  • 同步(Synchronization):兩個或兩個以上的進程或線程在運行過程中協同步調,按預定的先後次序運行。即就是線程之間如何通信、協作的問題。
  • 對象池(Object Pool): 指的是一次性創建出 N 個對象,之後所有的線程重複利用這 N 個對象,當然對象在被釋放前,也是不允許其他線程使用的, 一般指保存實例對象的容器。

基本概述

在Java領域中,我們可以將鎖大致分爲基於Java語法層面(關鍵詞)實現的鎖和基於JDK層面實現的鎖。

在Java領域中, 尤其是在併發編程領域,對於多線程併發執行一直有兩大核心問題:同步和互斥。其中:

  • 互斥(Mutual Exclusion):一個公共資源同一時刻只能被一個進程或線程使用,多個進程或線程不能同時使用公共資源。即就是同一時刻只允許一個線程訪問共享資源的問題。
  • 同步(Synchronization):兩個或兩個以上的進程或線程在運行過程中協同步調,按預定的先後次序運行。即就是線程之間如何通信、協作的問題。

針對對於這兩大核心問題,利用管程是能夠解決和實現的,因此可以說,管程是併發編程的萬能鑰匙。
雖然,Java在基於語法層面(synchronized 關鍵字)實現了對管程技術,但是從使用方式和性能上來說,內置鎖(synchronized 關鍵字)的粒度相對過大,不支持超時和中斷等問題。
爲了彌補這些問題,從JDK層面對其“重複造輪子”,在JDK內部對其重新設計和定義,甚至實現了新的特性。
在Java領域中,從JDK源碼分析來看,基於JDK層面實現的鎖大致主要可以分爲以下4種方式:

  • 基於Lock接口實現的鎖:JDK1.5版本提供的ReentrantLock類
  • 基於ReadWriteLock接口實現的鎖:JDK1.5版本提供的ReentrantReadWriteLock類
  • 基於AQS基礎同步器實現的鎖:JDK1.5版本提供的併發相關的同步器Semaphore,CyclicBarrier以及CountDownLatch等�
  • 基於自定義API操作實現的鎖:JDK1.8版本中提供的StampedLock類

從閱讀源碼不難發現,在Java SDK 併發包主要通過AbstractQueuedSynchronizer(AQS)實現多線程同步機制的封裝與定義,而通過Lock 和 Condition 兩個接口來實現管程,其中 Lock 用於解決互斥問題,Condition 用於解決同步問題。


一.AQS基礎同步器基本理論

在Java領域中,同步器是專門爲多線程併發設計的同步機制,主要是多線程併發執行時線程之間通過某種共享狀態來實現同步,只有當狀態滿足這種條件時線程才往下執行的一種同步機制。


一個標準的AQS同步器主要有同步狀態機制,等待隊列,條件隊列,獨佔模式,共享模式等五大核心要素組成。
在Java領域中,JDK的JUC(java.util.concurrent.)包中提供了各種併發工具,但是大部分同步工具的實現基於AbstractQueuedSynchronizer類實現,其內部結構主要如下:

  • 同步狀態機制(Synchronization Status):主要用於實現鎖(Lock)機制,是指同步狀態,其要求對於狀態的更新必須原子性的
  • 等待隊列(Wait Queue):主要用於存放等待線程獲取到的鎖資源,並且把線程維護到一個Node(節點)裏面和維護一個非阻塞的CHL Node FIFO(先進先出)隊列,主要是採用自旋鎖+CAS操作來保證節點插入和移除的原子性操作。
  • 條件隊列(Condition Queue):用於實現鎖的條件機制,一般主要是指替換“等待-通知”工作機制,主要是通過ConditionObject對象實現Condition接口提供的方法實現。
  • 獨佔模式(Exclusive Mode):主要用於實現獨佔鎖,主要是基於靜態內部類Node的常量標誌EXCLUSIVE來標識該節點是獨佔模式
  • 共享模式(Shared Mode):主要用於實現共享鎖,主要是基於靜態內部類Node的常量標誌SHARED來標識該節點是共享模式

我們可以得到一個比較通用的併發同步工具基礎模型,大致包含如下幾個內容,其中:

  • 條件變量(Conditional Variable): 利用線程間共享的變量進行同步的一種工作機制
  • 共享變量((Shared Variable)):一般指對象實體對象的成員變量和屬性
  • 阻塞隊列(Blocking Queue):共享變量(Shared Variable)及其對共享變量的操作統一封裝
  • 等待隊列(Wait Queue):每個條件變量都對應有一個等待隊列(Wait Queue),內部需要實現入隊操作(Enqueue)和出隊操作(Dequeue)方法
  • 變量狀態描述機(Synchronization Status):描述條件變量和共享變量之間狀態變化,又可以稱其爲同步狀態
  • 工作模式(Operation Mode): 線程資源具有排他性,因此定義獨佔模式和共享模式兩種工作模式

綜上所述,條件變量和等待隊列的作用是解決線程之間的同步問題;共享變量與阻塞隊列的作用是解決線程之間的互斥問題。

二. JDK顯式鎖統一概念模型

在併發編程領域,有兩大核心問題:一個是互斥,即同一時刻只允許一個線程訪問共享資源;另一個是同步,即線程之間如何通信、協作。

綜合Java領域中的併發鎖的各種實現與應用分析來看,一把鎖或者一種鎖,基本上都會包含以下幾個方面:

  • 鎖的同步器工作機制:主要是考慮共享模式還是獨享模式,是否支持超時機制,以及是否支持超時機制?
  • 鎖的同步器工作模式:主要是基於AQS基礎同步器封裝內部同步器,是否考慮公平/非公平模式?
  • 鎖的狀態變量機制: 主要鎖的狀態設置,是否共享狀態變量?
  • 鎖的隊列封裝定義:主要是指等待隊列和條件隊列,是否需要條件隊列或者等待隊列定義?
  • 鎖的底層實現操作: 主要是指底層CL鎖和CAS操作,是否需要考慮自旋鎖或者CAS操作實例對象方法?
  • 鎖的組合實現新鎖: 主要是基於獨佔鎖和共享鎖,是否考慮對應API自定義操作實現?

綜上所述,大致可以根據上述這些方向,我們便可以清楚🉐️知道Java領域中各種鎖實現的基本理論時和實現思想。

三.ReentrantLock(可重入鎖)的設計與實現

在Java領域中,ReentrantLock(可重入鎖)是針對於Java多線程併發控制中對一個線程可以多次對某個鎖進行加鎖操作,主要是基於內置的AQS基礎抽象隊列同步器實現的一種併發控制工具類。


一般來說,對於同一個線程是否可以重複佔有同一個鎖對象的角度來分,大致主要可以分爲可重入鎖與不可重入鎖。其中:

  • 可重入鎖:一個線程可以多次搶佔同一個鎖,也就意味着能夠支持一個線程對資源的重複加鎖,或者說,一個線程可以多次進入同一個鎖所同步的臨界區代碼塊。
  • 不可重入鎖:一個線程只能搶佔一次同一個鎖,也就意味着在同一時刻只能有一個線程獲取到鎖,而其他獲取鎖的線程只能等待,只有擁有鎖的線程釋放了鎖後,其他的線程才能夠獲取鎖。

ReentrantLock是JDK中顯式鎖一個主要基於Lock接口API實現的基礎實現類,擁有與內置鎖(synchronized)相同的併發性和內存語義,同時提供了限時搶佔、可中斷搶佔等一些高級鎖特性。
除此之外,ReentrantLock基於內置的AQS基礎抽象隊列同步器實現,在線程參與鎖資源競爭比較激烈的場景下,能表現出比內置鎖較佳的性能。
而且,ReentrantLock是一種獨佔鎖,在獨佔模式下只能逐一使用鎖,也就是說,任意時刻最多隻會有一個線程持有鎖的控制權。

1. 設計思想

ReentrantLock類最早是在JDK1.5版本提供的,從設計思想上來看,主要包括同步器工作模式,獲取鎖方法,釋放鎖方法以及定義Condition隊列方法等4個核心要素。其中:

  • 實現Lock接口 :主要基於Lock接口API實現對應方法,擁有與內置鎖(synchronized)相同的併發性和內存語義,用於支持和解決解決互斥問題。
  • 同步器工作模式:基於AQS基礎抽象隊列同步器封裝內置實現一個靜態的內置同步器抽象類,然後基於這個抽象類分別實現了公平同步器和非公平同步器,用來指定和描述同步器工作模式是公平模式還是非公平模式。
  • 公平/非公平模式:主要描述的是多個線程在同時獲取鎖時是否按照先到先得的順序獲取鎖,如果是則爲公平模式,否則爲非公平模式。
  • 獲取鎖方法:主要定義了一個lock()方法來獲取鎖,表示假如鎖已經被其他線程佔有或持有,其當前獲取鎖的線程則進入等待狀態。
  • 釋放鎖方法:主要定義了一個unlock()方法來釋放鎖,表示假如鎖已經被其他線程放棄或釋放,其當前獲取鎖的線程則獲得該鎖。
  • 定義Condition隊列操作方法: 主要是基於Condition接口來定義一個方法實現鎖的條件機制,用於支持線程的阻塞和喚醒功能即就是解決同步問題,也就是我們說的線程間的通信方式。
  • 定義等待隊列操作方法: 主要是依據條件隊列來時進行對應的操作,間接適配AQS基礎同步器中對於等待隊列的功能,保證獲取鎖的順序的公平性

2. 基本實現

在ReentrantLock類的JDK1.8版本中,對於ReentrantLock的基本實現如下:

public class ReentrantLock implements Lock, java.io.Serializable {

    private static final long serialVersionUID = 7373984872572414699 L;

    /**
     * ReentrantLock鎖-定義支持同步器實現
     */
    private final Sync sync;

    /**
     * ReentrantLock鎖-基於AQS定義支持同步器實現
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860 L;

        /**
         * ReentrantLock鎖-定義支持同步器Sync獲取鎖方法
         */
        abstract void lock();
				
        //......其他方法代碼
    }

    /**
     * ReentrantLock鎖-構造同步器默認工作模式(默認非公平模式)
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * ReentrantLock鎖-構造同步器指定工作模式(可選公平/非公平模式)
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    /**
     * ReentrantLock鎖-獲取鎖(普通模式)
     */
    public void lock() {
        sync.lock();
    }

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

    /**
     * ReentrantLock鎖-創建鎖的條件機制
     */
    public Condition newCondition() {
        return sync.newCondition();
    }

    //......其他方法代碼
}
  • 內部同步器:基於AQS基礎同步器封裝和定義了一個靜態內部Sync抽象類,其中抽象了一個內置鎖lock()方法
  • 同步器工作模式:提供了 2個構造方法,其中無參數構造方法表示的是默認的工作模式,有參數構造方法主要依據參數來實現指定的工作模式
  • 獲取鎖: 主要是提供了lock()方法,調用的靜態內部Sync抽象類內置鎖lock()方法,而本質上是AQS同步器中的acquire()方法
  • 釋放鎖: 主要是提供了unlock()方法,而本質上是調用的AQS同步器中的release()方法
  • 創建條件隊列: 主要是基於Condition接口定義了newCondition() 方法,調用的靜態內部Sync抽象類ewCondition()方法,而本質上是調用的AQS同步器中的ConditionObject中的newCondition()方法

2.1 基於AQS同步器封裝靜態內部Sync抽象類


    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * ReentrantLock鎖-內部同步器Sync的內置加鎖方法
         */
        abstract void lock();

        /**
         * ReentrantLock鎖-內部同步器Sync的非公平獲取鎖
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        /**
         * ReentrantLock鎖-內部同步器Sync的嘗試釋放
         */
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }


        /**
         * ReentrantLock鎖-內部同步器Sync的檢查線程是否獨佔
         */
        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        /**
         * ReentrantLock鎖-內部同步器Sync的條件機制
         */
        final ConditionObject newCondition() {
            return new ConditionObject();
        }


        /**
         * ReentrantLock鎖-內部同步器Sync的判斷鎖持有者
         */
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        /**
         * ReentrantLock鎖-內部同步器Sync的獨佔狀態
         */
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        /**
         * ReentrantLock鎖-內部同步器Sync的是否被鎖
         */
        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * ReentrantLock鎖-內部同步器Sync的流化處理對象
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
				
    }
  • Sync類:FairSync公平同步器和NonfairSync非公平同步器的抽象父類。
  • 校驗isHeldExclusively()方法: ReentrantLock鎖是屬於獨佔模式,需要當前鎖持有線程與當前線程是否一致
  • nonfairTryAcquire()方法: 一般主要用於非公平模式獲取鎖,其核心是compareAndSetState方法和setExclusiveOwnerThread方法
  • tryRelease()方法: 其公平/非公平模式都是通過ryRelease()來釋放鎖操作
  • newCondition()方法: 基於AQS同步器的ConditionObject對象封裝實現,提供給 ReentrantLock類使用
  • 私有readObject()方法:對於輸入的對象進行流化處理

特別需要注意的是,我們需要重點關注nonfairTryAcquire()方法和tryRelease()方法,其中:

  • 獲取非公平鎖 nonfairTryAcquire()方法:主要是用於獲取AQS的狀態變量status,其默認取值範圍是0和1,其中,0表示未被加鎖,1表示已經被加鎖
    • 如果狀態變量status=0,使用compareAndSetState方法進行CAS原子修改操作,把狀態變量修改爲1,並且通過setExclusiveOwnerThread設置當前線程爲鎖的持有線程
    • 如果狀態變量status=1,表示當前線程爲鎖的持有線程,正在進入鎖重入操作,狀態變量累加1,超過重入次數時,會拋出throw new Error("Maximum lock count exceeded")
  • 釋放鎖tryRelease()方法:主要是檢查當前線程是否爲鎖持有線程,隨後AQS同步器狀態變量減1,如果不是 throw new IllegalMonitorStateException()
    • 如果狀態變量status=0,表示鎖已經釋放成功,通過setExclusiveOwnerThread設置鎖的持有線程爲null,也就是置空鎖的持有線程
    • 如果狀態變量status !=0,  需要狀態變量遞減1即可,直到鎖已經釋放成功

2.2 基於Sync抽象類封裝FairSync公平同步器

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        /**
         * ReentrantLock鎖-公平模式-獲取鎖
         */
        final void lock() {
            acquire(1);
        }

        /**
         * ReentrantLock鎖-公平模式-嘗試獲取鎖
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
  • 實現方式: 主要基於AQS封裝的內部靜態抽象Sync同步類實現,使用的AQS的獨佔模式。
  • 主要方法: 主要提供了lock()和tryAcquire()方法,其嚴格意義上來說,僅僅只是實現了tryAcquire()方法,但是最關鍵的使用hasQueuedPredecessors來保證了鎖的公平性。
  • 鎖獲取方式: 主要是採用完全通過隊列來實現實現公平機制,即就是檢查是否存在等待隊列,如果隊列之中已經存在其他線程,直接放棄操作。

2.3 基於Sync抽象類封裝NonfairSync非公平同步器


    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * ReentrantLock鎖-非公平模式-獲取鎖
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        /**
         * ReentrantLock鎖-非公平模式-嘗試獲取鎖
         */
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
  • 實現方式: 主要基於AQS封裝的內部靜態抽象Sync同步類實現,使用的AQS的獨佔模式。
  • 主要方法: 主要提供了lock()和tryAcquire()方法,其嚴格意義上來說,僅僅只是實現了tryAcquire()方法,直接調用了Sync同步類的nonfairTryAcquire()方法。
  • 鎖獲取方式: 主要是採用闖入策略來打破鎖的公平,也就是一般準備獲取鎖的線程會先嚐試獲取鎖,失敗之後才進入隊列中。

3. 具體實現

在ReentrantLock類的JDK1.8版本中,對於ReentrantLock的具體實現如下:


public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699 L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    /**
     * ReentrantLock鎖-基於AQS定義支持同步器實現
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860 L;

        /**
         * ReentrantLock鎖-定義支持同步器Sync獲取鎖方法
         */
        abstract void lock();
				
        //......其他方法代碼
    }

    /**
     * ReentrantLock鎖-構造同步器默認工作模式(默認非公平模式)
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * ReentrantLock鎖-構造同步器指定工作模式(可選公平/非公平模式)
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    /**
     * ReentrantLock鎖-獲取鎖(普通模式)
     */
    public void lock() {
        sync.lock();
    }

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

    /**
     * ReentrantLock鎖-創建鎖的條件機制
     */
    public Condition newCondition() {
        return sync.newCondition();
    }
		
    /**
     * ReentrantLock鎖-獲取鎖(支持可中斷機制)
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * ReentrantLock鎖-嘗試獲取鎖(普通模式)
     */
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    /**
     * ReentrantLock鎖-嘗試獲取鎖(支持超時)
     */
    public boolean tryLock(long timeout, TimeUnit unit)
    throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    /**
     * ReentrantLock鎖-統計當前線程所持有數量
     */
    public int getHoldCount() {
        return sync.getHoldCount();
    }


    /**
     * ReentrantLock鎖-檢測當前線程是否獨佔
     */
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

    /**
     * ReentrantLock鎖-檢測是否被加鎖
     */
    public boolean isLocked() {
        return sync.isLocked();
    }

    /**
     * ReentrantLock鎖-檢測是否公平模式
     */
    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    /**
     * ReentrantLock鎖-獲取當前鎖持有線程
     */
    protected Thread getOwner() {
        return sync.getOwner();
    }

    /**
     * ReentrantLock鎖-檢測輪詢線程是否存在隊列中
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    /**
     * ReentrantLock鎖-檢測線程是否存在隊列中
     */
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    /**
     * ReentrantLock鎖-獲取隊列數量
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    /**
     * ReentrantLock鎖-獲取隊列中的所有線程
     */
    protected Collection < Thread > getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    /**
     * ReentrantLock鎖-檢測存在條件隊列是否入隊狀態
     */
    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject) condition);
    }

    /**
     * ReentrantLock鎖-獲取等待隊列的長度
     */
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject) condition);
    }

    /**
     * ReentrantLock鎖-獲取等待隊列的線程對象
     */
    protected Collection < Thread > getWaitingThreads(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject) condition);
    }

}
  • 獲取鎖的方法:主要提供了一般模式lock()方法,支持可中斷機制lockInterruptibly()方法,無參數tryLock()方法以及有參數的支持超時機制的tryLock(long timeout, TimeUnit unit)方法
  • 釋放鎖的方法:主要是unlock()方法,間接調用是內部同步器中的release()方法
  • 條件隊列操作:主要提供了獲取隊列中的線程對象getQueuedThreads(),檢測隊列入隊hasWaiters(Condition condition) 方法,以及
  • 等待隊列操作:主要提供了獲取隊列中的線程對象getWaitingThreads(Condition condition),檢測隊列入隊hasQueuedThread(Thread thread) 方法,以及獲取隊列長度getQueueLength()方法和getWaitingThreads(Condition condition)方法
  • 其他檢測判斷:主要有判斷是否公平模式isFair()方法,是否當前線程獨佔isHeldByCurrentThread()方法,以及是否加鎖 isLocked()等

需要注意的是,在JDK1.8版本之後,對於ReentrantLock的實現有些細微的變化,感興趣的可自行參考相關版本的源碼進行對比分析。

綜上所述,從一定意義上講,ReentrantLock是一種可重入的獨佔(互斥)鎖,屬於AQS基礎抽象隊列同步器中獨佔模式孵化的產物,支持公平模式與非公平模式,默認採用非公平模式。

寫在最後

通過對Java領域中,JDK內部提供的各種鎖的實現來看,一直圍繞的核心主要還是基於AQS基礎同步器來實現的,但是AQS基礎同步器不是一種非它不可的技術標準規範,更多的只是一套技術參考指南。

但是,實際上,Java對於鎖的實現與運用遠遠不止這些,還有相位器(Phaser)和交換器(Exchanger),以及在Java JDK1.8版本之前併發容器ConcurrentHashMap中使用的分段鎖(Segment)。

不論是何種實現和應用,在Java併發編程領域來講,都是圍繞線程安全問題的角度去考慮的,只是針對於各種各樣的業務場景做的具體的實現。

一定意義上來講,對線程加鎖只是併發編程的實現方式之一,相對於實際應用來說,Java領域中的鎖都只是一種單一應用的鎖,只是給我們掌握Java併發編程提供一種思想沒,三言兩語也不可能詳盡。

到此爲止,這算是對於Java領域中併發鎖的最終章,文中表述均爲個人看法和個人理解,如有不到之處,忘請諒解也請給予批評指正。

最後,技術研究之路任重而道遠,願我們熬的每一個通宵,都撐得起我們想在這條路上走下去的勇氣,未來仍然可期,與各位程序編程君共勉!

版權聲明:本文爲博主原創文章,遵循相關版權協議,如若轉載或者分享請附上原文出處鏈接和鏈接來源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章