源碼解讀系列之: ReentrantLock

ReentrantLock是java1.5中l(wèi)ock框架中Lock接口的一個(gè)實(shí)現(xiàn)類.一個(gè)ReentrantLock的實(shí)例鎖擁有和synchronized相同的行為和語義,并且還擴(kuò)展了其他能力.
ReentrantLock是通過一種什么機(jī)制來實(shí)現(xiàn)鎖的呢?也就是說ReentrantLock到底是鎖住了什么東西來控制線程同步的呢?下面將詳細(xì)講解.
ReentrantLock內(nèi)部實(shí)現(xiàn)了一個(gè)AbstractQueuedSynchronizer的同步器,ReentrantLock就是通過控制這個(gè)AbstractQueuedSynchronizer同步器來實(shí)現(xiàn)多個(gè)線程之間的同步.那么具體的實(shí)現(xiàn)原理是怎么樣的呢?
AbstractQueuedSynchronizer類會(huì)維護(hù)一個(gè)等待隊(duì)列,并且擁有一個(gè)state(volatile修飾)的成員變量屬性,AbstractQueuedSynchronizer就是通過這個(gè)state來控制多個(gè)線程的同步訪問的.當(dāng)ReentrantLock調(diào)用lock()方法時(shí),內(nèi)部實(shí)際調(diào)用的是Sync(AbstractQueuedSynchronizer的實(shí)現(xiàn)類)的lock方法,此方法會(huì)先判斷AbstractQueuedSynchronizer中state屬性的值:如果state!=0,說明當(dāng)前有線程在占用鎖資源,然后接著判斷當(dāng)前占用該鎖資源的線程是否跟當(dāng)前線程是同一個(gè)線程,如果是同一個(gè)線程那么state值就加一,同時(shí)當(dāng)前線程繼續(xù)執(zhí)行,如果不是同一個(gè)線程,那么就會(huì)把當(dāng)前線程加入等待隊(duì)列(并且會(huì)一直嘗試獲取鎖資源).如果state==0,說明當(dāng)前鎖資源是可用,那么直接設(shè)置當(dāng)前線程占用了鎖資源并返回繼續(xù)執(zhí)行.執(zhí)行完成之后,必須要手動(dòng)釋放鎖資源.


下面對ReentrantLock的源碼并相關(guān)類源碼進(jìn)行解讀:

類定義

public class ReentrantLock implements Lock, java.io.Serializable

成員變量

修飾符 變量名 作用
private final Sync sync 實(shí)際同步鎖控制實(shí)例

構(gòu)造方法

無參構(gòu)造方法
無參構(gòu)造方法會(huì)給sync賦值,默認(rèn)賦值為不公平鎖同步(公平鎖,不公平鎖下面會(huì)講)

public ReentrantLock() {
    sync = new NonfairSync();
}

有參構(gòu)造方法
參數(shù):
true 公平鎖,線程獲取鎖的順序跟等待的時(shí)間有關(guān),先等待的線程先獲取鎖
false 不公平鎖,線程獲取鎖是隨機(jī)的

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

核心方法講解

lock()方法

public void lock() {
    // 調(diào)用Sync(Sync是AbstractQueuedSynchronizer的子類)的lock()方法
    // Sync是ReentrantLock的內(nèi)部類,同時(shí)在ReentrantLock中有兩種實(shí)現(xiàn)方式
    // 1. FairSync(公平實(shí)現(xiàn))
    // 2. NonFairSync(不公平實(shí)現(xiàn))
    sync.lock();
}

-- ------------------------------------------------------ --
-- ---------------FairSync獲取鎖的實(shí)現(xiàn)-------------------- --
-- ------------------------------------------------------ --
/**
* FairSync的lock方法實(shí)現(xiàn)
**/
final void lock() {
    // acquire方法是AbstractQueuedSynchronizer中的方法
    // 此方法會(huì)調(diào)用tryAcquire(int)方法來試圖獲取鎖資源
    acquire(1);
}

/**
* AbstractQueuedSynchronizer中acquire()方法的實(shí)現(xiàn)
**/
public final void acquire(int arg) {
    // 試圖獲取鎖資源(會(huì)調(diào)用對應(yīng)實(shí)現(xiàn)的tryAcquire()方法),
    // 不成功則加入等待隊(duì)列并獲取隊(duì)列(addWaiter()會(huì)將當(dāng)前線程加入到等待隊(duì)列尾部)
    // acquireQueued()(不知道怎么說,等會(huì)直接講代碼)
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

/**
* FairSync中tryAcquire()的實(shí)現(xiàn)
* 返回
*   true: 獲取鎖成功
*   false: 獲取鎖不成功
**/
protected final boolean tryAcquire(int acquires) {
    // 獲取當(dāng)前線程
    final Thread current = Thread.currentThread();
    // 獲取鎖資源的狀態(tài)
    // 0: 說明當(dāng)前鎖可立即獲取,在此種狀態(tài)下(又是公平鎖)
    // >0并且當(dāng)前線程與持有鎖資源的線程是同一個(gè)線程則state + 1并返回true
    // >0并且占有鎖資源的不是當(dāng)前線程,則返回false表示獲取不成功
    int c = getState();
    if (c == 0) {
        // 在鎖可以立即獲取的情況下
        // 首先判斷線程是否是剛剛釋放鎖資源的頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)(線程的等待先后順序)
        // 如果是等待時(shí)間最長的才會(huì)馬上獲取到鎖資源,否則不會(huì)(這也是公平與不公平的主要區(qū)別所在)
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {  //線程可以遞歸獲取鎖
        int nextc = c + acquires;
        // 超過int上限值拋出錯(cuò)誤
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

/**
* AbstractQueuedSynchronizer中acquireQueued()方法講解
**/
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        // 注意這里的無限循環(huán)(表現(xiàn)出來就是等待的一個(gè)過程)
        for (;;) {
            // 獲得前一個(gè)非null節(jié)點(diǎn)
            final Node p = node.predecessor();
            // 如果前任節(jié)點(diǎn)是頭結(jié)點(diǎn)(頭節(jié)點(diǎn)是表示獲取到了資源鎖的節(jié)點(diǎn))
            // 并且試圖獲取鎖資源(只有在p節(jié)點(diǎn)release()掉鎖資源才會(huì)獲取成功)
            // 如果獲取鎖資源成功,就將此線程節(jié)點(diǎn)設(shè)置為頭結(jié)點(diǎn),并把p節(jié)點(diǎn)的引用斷開
            // 獲取鎖成功就退出循環(huán)
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            
            // 如果獲取資源失敗了,那就先判斷線程是否需要被阻塞,需要就阻塞線程
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
                
            // 繼續(xù)循環(huán)等待
        }
    } finally {
        // 如果獲取鎖資源失敗了,
        // 那么就把線程的等待狀態(tài)設(shè)置為cancelled(此狀態(tài)的線程不會(huì)再獲得鎖資源)
        if (failed)
            cancelAcquire(node);
    }
}


-- ------------------------------------------------------ --
-- ---------------NonFairSync獲取鎖的實(shí)現(xiàn)----------------- --
-- ------------------------------------------------------ --
/**
* lock()方法實(shí)現(xiàn)
**/
final void lock() {
    // 如果鎖空閑則立即獲取鎖資源,設(shè)置鎖資源的當(dāng)前占用線程
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // acquire()過程跟FairSync是一樣的,
        // 主要區(qū)別在于NonFairSync的tryAcqure()有不同的實(shí)現(xiàn)
        acquire(1);
}

/**
* tryAcquire()方法實(shí)現(xiàn)
* 調(diào)用的nonfairTryAcquire()方法,這是父類Sync中的方法實(shí)現(xiàn)
**/
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

/**
* Sync中的nonfairTryAcquire()方法實(shí)現(xiàn)
* 這個(gè)跟公平類中的實(shí)現(xiàn)主要區(qū)別在于不會(huì)判斷當(dāng)前線程是否是等待時(shí)間最長的線程
**/ 
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 跟FairSync中的主要區(qū)別,不會(huì)判斷hasQueuedPredecessors()
        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;
}

unlock()方法
釋放線程占用的鎖

public void unlock() {
    // 調(diào)用Sync中的release()方法,所以公平和不公平類釋放鎖是一樣的
    // 實(shí)際調(diào)用AbstractQueuedSynchronizer中的release()
    sync.release(1);
}

/**
* AbstractQueuedSynchronizer中的release()
**/
public final boolean release(int arg) {
    // 釋放鎖資源,子類會(huì)重寫這個(gè)方法(在這里就是調(diào)用的Sync中tryRelease())
    if (tryRelease(arg)) {
        // 釋放鎖資源成功后,會(huì)執(zhí)行一個(gè)喚醒后續(xù)線程(喚醒一個(gè))的操作
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

/**
* Sync中tryRelease()
**/
protected final boolean tryRelease(int releases) {
    // 修改當(dāng)前鎖的狀態(tài)
    // 如果一個(gè)線程遞歸獲取了該鎖(也就是state != 1), 那么c可能不等0
    // 如果沒有線程遞歸獲取該鎖,則c == 0
    int c = getState() - releases;
    
    // 如果鎖的占有線程不等于當(dāng)前正在執(zhí)行釋放操作的線程,則拋出異常
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // c == 0,表示當(dāng)前線程釋放鎖成功,同時(shí)表示遞歸獲取了該鎖的線程已經(jīng)執(zhí)行完畢
    // 則設(shè)置當(dāng)前鎖狀態(tài)為free,同時(shí)設(shè)置鎖的當(dāng)前線程為null,可以讓其他線程來獲取
    // 同時(shí)也說明,如果c != 0,則表示線程遞歸占用了鎖資源,
    // 所以鎖的當(dāng)前占用線程依然是當(dāng)前釋放鎖的線程(實(shí)際沒有釋放)
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 重新設(shè)置鎖的占有數(shù)
    setState(c);
    return free;
}

條件鎖的操作

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

這里不對源碼進(jìn)行解讀,只對原理進(jìn)行一個(gè)說明,上述函數(shù)實(shí)際上是執(zhí)行了一個(gè)new ConditionObject();的操作,  
這個(gè)類是同步器中的一個(gè)內(nèi)部類,這個(gè)類內(nèi)部是維護(hù)了一個(gè)條件隊(duì)列,條件鎖的操作也是針對這個(gè)條件隊(duì)列的一個(gè)操作.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-03】 更新日志 前言 在java中,鎖是實(shí)現(xiàn)并發(fā)的關(guān)鍵組件,多個(gè)...
    一字馬胡閱讀 44,326評論 1 32
  • 一、多線程 說明下線程的狀態(tài) java中的線程一共有 5 種狀態(tài)。 NEW:這種情況指的是,通過 New 關(guān)鍵字創(chuàng)...
    Java旅行者閱讀 4,868評論 0 44
  • 第三章 Java內(nèi)存模型 3.1 Java內(nèi)存模型的基礎(chǔ) 通信在共享內(nèi)存的模型里,通過寫-讀內(nèi)存中的公共狀態(tài)進(jìn)行隱...
    澤毛閱讀 4,503評論 2 21
  • 前言 上一篇文章《基于CAS操作的Java非阻塞同步機(jī)制》 分析了非同步阻塞機(jī)制的實(shí)現(xiàn)原理,本篇將分析一種以非同步...
    Mars_M閱讀 4,923評論 5 9
  • 蔥油餅 燒鴨面 炸醬麵 菜花餃 啦啦啦,每天都在吃的路上 哈哈哈,這種感覺真好
    動(dòng)動(dòng)小肥肥閱讀 1,020評論 0 1

友情鏈接更多精彩內(nèi)容