最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java底層AQS實現(xiàn)類ReentrantLock鎖的構(gòu)成及源碼解析

 更新時間:2022年10月09日 14:45:50   作者:Q.E.D  
本章我們就要來學(xué)習一下第一個?AQS?的實現(xiàn)類:ReentrantLock,看看其底層是如何組合?AQS?,實現(xiàn)了自己的那些功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步

引導(dǎo)語

本章的描述思路是先描述清楚 ReentrantLock 的構(gòu)成組件,然后使用加鎖和釋放鎖的方法把這些組件串起來。

1、類注釋

ReentrantLock 中文我們習慣叫做可重入互斥鎖,可重入的意思是同一個線程可以對同一個共享資源重復(fù)的加鎖或釋放鎖,互斥就是 AQS 中的排它鎖的意思,只允許一個線程獲得鎖。

我們來一起來看下類注釋上都有哪些重要信息:

  • 可重入互斥鎖,和 synchronized 鎖具有同樣的功能語義,但更有擴展性;
  • 構(gòu)造器接受 fairness 的參數(shù),fairness 是 ture 時,保證獲得鎖時的順序,false 不保證;
  • 公平鎖的吞吐量較低,獲得鎖的公平性不能代表線程調(diào)度的公平性;
  • tryLock() 無參方法沒有遵循公平性,是非公平的(lock 和 unlock 都有公平和非公平,而 tryLock 只有公平鎖,所以單獨拿出來說一說)。

我們補充一下第二點,ReentrantLock 的公平和非公平,是針對獲得鎖來說的,如果是公平的,可以保證同步隊列中的線程從頭到尾的順序依次獲得鎖,非公平的就無法保證,在釋放鎖的過程中,我們是沒有公平和非公平的說法的。

2、類結(jié)構(gòu)

ReentrantLock 類本身是不繼承 AQS 的,實現(xiàn)了 Lock 接口,如下:

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

Lock 接口定義了各種加鎖,釋放鎖的方法,接口有如下幾個:

// 獲得鎖方法,獲取不到鎖的線程會到同步隊列中阻塞排隊
void lock();
// 獲取可中斷的鎖
void lockInterruptibly() throws InterruptedException;
// 嘗試獲得鎖,如果鎖空閑,立馬返回 true,否則返回 false
boolean tryLock();
// 帶有超時等待時間的鎖,如果超時時間到了,仍然沒有獲得鎖,返回 false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 釋放鎖
void unlock();
// 得到新的 Condition
Condition newCondition();

ReentrantLock 就負責實現(xiàn)這些接口,我們使用時,直接面對的也是這些方法,這些方法的底層實現(xiàn)都是交給 Sync 內(nèi)部類去實現(xiàn)的,Sync 類的定義如下:

abstract static class Sync extends AbstractQueuedSynchronizer {}

Sync 繼承了 AbstractQueuedSynchronizer ,所以 Sync 就具有了鎖的框架,根據(jù) AQS 的框架,Sync 只需要實現(xiàn) AQS 預(yù)留的幾個方法即可,但 Sync 也只是實現(xiàn)了部分方法,還有一些交給子類 NonfairSync 和 FairSync 去實現(xiàn)了,NonfairSync 是非公平鎖,F(xiàn)airSync 是公平鎖,定義如下:

// 同步器 Sync 的兩個子類鎖
static final class FairSync extends Sync {}
static final class NonfairSync extends Sync {}

幾個類整體的結(jié)構(gòu)如下:

圖片描述

圖中 Sync、NonfairSync、FairSync 都是靜態(tài)內(nèi)部類的方式實現(xiàn)的,這個也符合 AQS 框架定義的實現(xiàn)標準。

3、構(gòu)造器 

ReentrantLock 構(gòu)造器有兩種,代碼如下:

// 無參數(shù)構(gòu)造器,相當于 ReentrantLock(false),默認是非公平的
public ReentrantLock() {
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

無參構(gòu)造器默認構(gòu)造是非公平的鎖,有參構(gòu)造器可以選擇。

從構(gòu)造器中可以看出,公平鎖是依靠 FairSync 實現(xiàn)的,非公平鎖是依靠 NonfairSync 實現(xiàn)的。

4、Sync 同步器

Sync 表示同步器,繼承了 AQS,UML 圖如下:

圖片描述

從 UML 圖中可以看出,lock 方法是個抽象方法,留給 FairSync 和 NonfairSync 兩個子類去實現(xiàn),我們一起來看下剩余重要的幾個方法。

4.1、nonfairTryAcquire 

// 嘗試獲得非公平鎖
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 同步器的狀態(tài)是 0,表示同步器的鎖沒有人持有
    if (c == 0) {
        // 當前線程持有鎖
        if (compareAndSetState(0, acquires)) {
            // 標記當前持有鎖的線程是誰
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 如果當前線程已經(jīng)持有鎖了,同一個線程可以對同一個資源重復(fù)加鎖,代碼實現(xiàn)的是可重入鎖
    else if (current == getExclusiveOwnerThread()) {
        // 當前線程持有鎖的數(shù)量 + acquires
        int nextc = c + acquires;
        // int 是有最大值的,<0 表示持有鎖的數(shù)量超過了 int 的最大值
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    //否則線程進入同步隊列
    return false;
}

以上代碼有三點需要注意:

通過判斷 AQS 的 state 的狀態(tài)來決定是否可以獲得鎖,0 表示鎖是空閑的;else if 的代碼體現(xiàn)了可重入加鎖,同一個線程對共享資源重入加鎖,底層實現(xiàn)就是把 state + 1,并且可重入的次數(shù)是有限制的,為 Integer 的最大值;這個方法是非公平的,所以只有非公平鎖才會用到,公平鎖是另外的實現(xiàn)。

無參的 tryLock 方法調(diào)用的就是此方法,tryLock 的方法源碼如下:

public boolean tryLock() {
    // 入?yún)?shù)是 1 表示嘗試獲得一次鎖
    return sync.nonfairTryAcquire(1);
}

4.2、tryRelease

// 釋放鎖方法,非公平和公平鎖都使用
protected final boolean tryRelease(int releases) {
    // 當前同步器的狀態(tài)減去釋放的個數(shù),releases 一般為 1
    int c = getState() - releases;
    // 當前線程根本都不持有鎖,報錯
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 如果 c 為 0,表示當前線程持有的鎖都釋放了
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 如果 c 不為 0,那么就是可重入鎖,并且鎖沒有釋放完,用 state 減去 releases 即可,無需做其他操作
    setState(c);
    return free;
}

tryRelease 方法是公平鎖和非公平鎖都公用的,在鎖釋放的時候,是沒有公平和非公平的說法的。

從代碼中可以看到,鎖最終被釋放的標椎是 state 的狀態(tài)為 0,在重入加鎖的情況下,需要重入解鎖相應(yīng)的次數(shù)后,才能最終把鎖釋放,比如線程 A 對共享資源 B 重入加鎖 5 次,那么釋放鎖的話,也需要釋放 5 次之后,才算真正的釋放該共享資源了。

5、FairSync 公平鎖

FairSync 公平鎖只實現(xiàn)了 lock 和 tryAcquire 兩個方法,lock 方法非常簡單,如下:

// acquire 是 AQS 的方法,表示先嘗試獲得鎖,失敗之后進入同步隊列阻塞等待
final void lock() {
    acquire(1);
}

tryAcquire 方法是 AQS 在 acquire 方法中留給子類實現(xiàn)的抽象方法,F(xiàn)airSync 中實現(xiàn)的源碼如下:

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // hasQueuedPredecessors 是實現(xiàn)公平的關(guān)鍵
        // 會判斷當前線程是不是屬于同步隊列的頭節(jié)點的下一個節(jié)點(頭節(jié)點是釋放鎖的節(jié)點)
        // 如果是(返回false),符合先進先出的原則,可以獲得鎖
        // 如果不是(返回true),則繼續(xù)等待
        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;
}

代碼和 Sync 的 nonfairTryAcquire 方法實現(xiàn)類似,唯一不同的是在獲得鎖時使用 hasQueuedPredecessors 方法體現(xiàn)了其公平性。

6、NonfairSync 非公平鎖

NonfairSync 底層實現(xiàn)了 lock 和 tryAcquire 兩個方法,如下:

// 加鎖
final void lock() {
    // cas 給 state 賦值
    if (compareAndSetState(0, 1))
        // cas 賦值成功,代表拿到當前鎖,記錄拿到鎖的線程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // acquire 是抽象類AQS的方法,
        // 會再次嘗試獲得鎖,失敗會進入到同步隊列中
        acquire(1);
}
// 直接使用的是 Sync.nonfairTryAcquire 方法 
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

7、如何串起來

以上內(nèi)容主要說了 ReentrantLock 的基本結(jié)構(gòu),比較零散,那么這些零散的結(jié)構(gòu)如何串聯(lián)起來呢?我們是通過 lock、tryLock、unlock 這三個 API 將以上幾個類串聯(lián)起來,我們來一一看下。

7.1 lock 加鎖

lock 的代碼實現(xiàn):

public void lock() {
    sync.lock();
}

其底層的調(diào)用關(guān)系(只是簡單表明調(diào)用關(guān)系,并不是完整分支圖)如下:

圖片描述

7.2 tryLock 嘗試加鎖 

 tryLock 有兩個方法,一種是無參的,一種提供了超時時間的入?yún)?,兩種內(nèi)部是不同的實現(xiàn)機制,代碼分別如下:

// 無參構(gòu)造器
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
// timeout 為超時的時間,在時間內(nèi),仍沒有得到鎖,會返回 false
public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

接著我們一起看下兩個 tryLock 的調(diào)用關(guān)系圖,下圖顯示的是無參 tryLock 的調(diào)用關(guān)系圖,如下:

圖片描述

我們需要注意的是 tryLock 無參方法底層走的就是非公平鎖實現(xiàn),沒有公平鎖的實現(xiàn)。

下圖展示的是帶有超時時間的有參 tryLock 的調(diào)用實現(xiàn)圖:

圖片描述

7.3 unlock 釋放鎖 

unlock 釋放鎖的方法,底層調(diào)用的是 Sync 同步器的 release 方法,release 是 AQS 的方法,分成兩步:

嘗試釋放鎖,如果釋放失敗,直接返回 false;釋放成功,從同步隊列的頭節(jié)點的下一個節(jié)點開始喚醒,讓其去競爭鎖。

第一步就是我們上文中 Sync 的 tryRelease 方法(4.1),第二步 AQS 已經(jīng)實現(xiàn)了。

unLock 的源碼如下:

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

7.4 Condition

ReentrantLock 對 Condition 并沒有改造,直接使用 AQS 的 ConditionObject 即可。

8、總結(jié)

這就是我們在研究完 AQS 源碼之后,碰到的第一個鎖,是不是感覺很簡單,AQS 搭建了整個鎖架構(gòu),子類鎖只需要根據(jù)場景,實現(xiàn) AQS 對應(yīng)的方法即可,不僅僅是 ReentrantLock 是這樣,JUC 中的其它鎖也都是這樣,只要對 AQS 了如指掌,鎖其實非常簡單。

以上就是java底層AQS實現(xiàn)類kReentrantLock鎖的構(gòu)成及源碼解析的詳細內(nèi)容,更多關(guān)于AQS實現(xiàn)類ReentrantLock鎖的構(gòu)成的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringMVC Hibernate與JPA使用教程

    SpringMVC Hibernate與JPA使用教程

    這篇文章主要介紹了SpringMVC Hibernate與JPA,在正式進入Hibernate的高級應(yīng)用之前,需要了解聲明是數(shù)據(jù)模型與領(lǐng)域模型,這兩個概念將會幫助我們更好的理解實體對象的關(guān)聯(lián)關(guān)系映射
    2022-12-12
  • 通過代碼快速理解Java的三種代理模式

    通過代碼快速理解Java的三種代理模式

    這篇文章主要介紹了通過代碼快速理解Java的三種代理模式,代理(Proxy)是一種設(shè)計模式,提供了對目標對象另外的訪問方式,即通過代理對象訪問目標對象。,需要的朋友可以參考下
    2019-06-06
  • 關(guān)于java中@Async異步調(diào)用詳細解析附代碼

    關(guān)于java中@Async異步調(diào)用詳細解析附代碼

    本文主要介紹了java關(guān)于@Async異步調(diào)用詳細解析附代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2022-07-07
  • Spring?MVC中的攔截器案例演示

    Spring?MVC中的攔截器案例演示

    攔截器可以攔截所有的請求,也可以只攔截滿足指定的請求,?Spring?MVC?的攔截器類似于過濾器,用來執(zhí)行預(yù)處理和后處理操作,本文給大家介紹Spring?MVC中的攔截器案例演示,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • 一文詳解如何在Java中啟動線程

    一文詳解如何在Java中啟動線程

    今天要跟大家聊一聊Java多線程的原理和使用方式,Java多線程是提高程序性能的重要機制,了解線程生命周期、同步機制、線程池和線程間通信等概念,可以幫助我們編寫出高效、可靠的多線程程序,需要的朋友可以參考下
    2024-07-07
  • SpringBoot多租戶配置與實現(xiàn)示例

    SpringBoot多租戶配置與實現(xiàn)示例

    本文詳細介紹了在SpringBoot中實現(xiàn)多租戶架構(gòu)的方法和步驟,包括配置數(shù)據(jù)源、Hibernate攔截器、租戶解析器等,以共享數(shù)據(jù)庫、共享數(shù)據(jù)表的方式,確保數(shù)據(jù)隔離和安全性,感興趣的可以了解一下
    2024-09-09
  • 實戰(zhàn)分布式醫(yī)療掛號系統(tǒng)開發(fā)醫(yī)院科室及排班的接口

    實戰(zhàn)分布式醫(yī)療掛號系統(tǒng)開發(fā)醫(yī)院科室及排班的接口

    這篇文章主要為大家介紹了實戰(zhàn)分布式醫(yī)療掛號系統(tǒng)開發(fā)醫(yī)院科室及排班的接口,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2022-04-04
  • IDEA設(shè)置允許一個類并行的方法

    IDEA設(shè)置允許一個類并行的方法

    這篇文章主要介紹了IDEA設(shè)置允許一個類并行的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • java保證對象在內(nèi)存中唯一性的實現(xiàn)方法

    java保證對象在內(nèi)存中唯一性的實現(xiàn)方法

    這篇文章主要介紹了java如何保證對象在內(nèi)存中的唯一性,如果創(chuàng)建多個對象的話,可能會引發(fā)出各種各樣的問題,這時,就需要我們保證這個對象在內(nèi)存中的唯一性,需要的朋友可以參考下
    2019-06-06
  • SpringCloud手寫Ribbon實現(xiàn)負載均衡

    SpringCloud手寫Ribbon實現(xiàn)負載均衡

    這篇文章主要介紹了SpringCloud手寫Ribbon實現(xiàn)負載均衡的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2021-01-01

最新評論

彭泽县| 龙游县| 康乐县| 定边县| 如东县| 玉林市| 福泉市| 论坛| 峡江县| 禄丰县| 塘沽区| 新巴尔虎左旗| 达州市| 岳西县| 中西区| 昭苏县| 怀来县| 弥勒县| 芦山县| 浮梁县| 新巴尔虎左旗| 黄山市| 玉门市| 宣汉县| 全椒县| 汉沽区| 龙山县| 南皮县| 化州市| 黑山县| 云安县| 台安县| 大理市| 大洼县| 利川市| 石柱| 滕州市| 北京市| 新密市| 西畴县| 慈溪市|