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

Java中的AQS框架原理詳解

 更新時間:2023年12月16日 09:16:48   作者:小晨想好好學(xué)習(xí)  
這篇文章主要介紹了Java中的AQS框架原理詳解,AQS核心思想是,如果被請求的共享資源(state)空閑,則將當(dāng)前請求資源的線程設(shè)置為有效的工作線程,并且將共享資源設(shè)置為鎖定狀態(tài),需要的朋友可以參考下

一、原理概述

AQS全稱是 AbstractQueuedSynchronizer,是阻塞式鎖和相關(guān)的同步器工具的框架

AQS核心思想是,如果被請求的共享資源(state)空閑,則將當(dāng)前請求資源的線程設(shè)置為有效的工作線程,并且將共享資源設(shè)置為鎖定狀態(tài)。如果被請求的共享資源被占用,那么就需要一套線程阻塞等待以及被喚醒時鎖分配的機制,這個機制AQS是用CLH隊列鎖實現(xiàn)的,即將暫時獲取不到鎖的線程加入到隊列中。

CLH隊列是一個虛擬的雙向隊列(虛擬的雙向隊列即不存在隊列實例,僅存在結(jié)點之間的關(guān)聯(lián)關(guān)系)。AQS是將每條請求共享資源的線程封裝成一個CLH鎖隊列的一個結(jié)點(Node)來實現(xiàn)鎖的分配。

AQS(AbstractQueuedSynchronizer)原理圖:

在這里插入圖片描述

AQS使用一個int成員變量來表示同步狀態(tài),通過內(nèi)置的FIFO隊列來完成獲取資源線程的排隊工作。AQS使用CAS對該同步狀態(tài)進行原子操作實現(xiàn)對其值的修改。

//共享變量,使用volatile修飾保證線程可見性
private volatile int state;
//狀態(tài)信息通過protected類型的getState,setState,compareAndSetState進行操作. 且為final類型,不允許被子類重寫
//返回同步狀態(tài)的當(dāng)前值
protected final int getState() {
        return state;
}
 // 設(shè)置同步狀態(tài)的值
protected final void setState(int newState) {
        state = newState;
}
//原子地(CAS操作)將同步狀態(tài)值設(shè)置為給定值update如果當(dāng)前同步狀態(tài)的值等于expect(期望值)
protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

二、AQS 對資源的共享方式

AQS定義兩種資源共享方式

  • Exclusive(獨占):只有一個線程能執(zhí)行,如ReentrantLock。又可分為公平鎖和非公平鎖: - 公平鎖:按照線程在隊列中的排隊順序,先到者先拿到鎖 - 非公平鎖:當(dāng)線程要獲取鎖時,無視隊列順序直接去搶鎖,誰搶到就是誰的
  • share(共享):多個線程都可以同時獲取到鎖,如Semaphore/CountDownLatch。Semaphore、CountDownLatch、 CyclicBarrier、ReadWriteLock 我們都會在后面講到。

不同的自定義同步器爭用共享資源的方式也不同。自定義同步器在實現(xiàn)時只需要實現(xiàn)共享資源 state 的獲取與釋放方式即可,至于具體線程等待隊列的維護(如獲取資源失敗入隊/喚醒出隊等),AQS已經(jīng)在頂層實現(xiàn)好了

三、AQS底層使用了模板方法模式

同步器的設(shè)計是基于模板方法模式的,如果需要自定義同步器一般的方式是這樣

  • 自定義同步器繼承AbstractQueuedSynchronizer并重寫指定的方法。(這些重寫方法很簡單,無非是對于共享資源state的獲取和釋放)
  • 將自定義同步器組合在自定義同步組件的實現(xiàn)中,并調(diào)用其模板方法,而這些模板方法會調(diào)用使用者重寫的方法

自定義同步器時需要重寫下面幾個AQS提供的模板方法:

isHeldExclusively()//該線程是否正在獨占資源。只有用到condition才需要去實現(xiàn)它。
tryAcquire(int)//獨占方式。嘗試獲取資源,成功則返回true,失敗則返回false。
tryRelease(int)//獨占方式。嘗試釋放資源,成功則返回true,失敗則返回false。
tryAcquireShared(int)//共享方式。嘗試獲取資源。負(fù)數(shù)表示失?。?表示成功,但沒有剩余可用資源;正數(shù)表示成功,且有剩余資源。
tryReleaseShared(int)//共享方式。嘗試釋放資源,成功則返回true,失敗則返回false。

默認(rèn)情況下,每個方法都拋出 UnsupportedOperationException。這些方法的實現(xiàn)必須是內(nèi)部線程安全的,并且通常應(yīng)該簡短而不是阻塞。

AQS類中的其他方法都是final ,所以無法被其他類使用,只有這幾個方法可以被其他類使用。

以ReentrantLock為例,state初始化為0,表示未鎖定狀態(tài)。A線程lock()時,會調(diào)用tryAcquire()獨占該鎖并將state+1。此后,其他線程再tryAcquire()時就會失敗,直到A線程unlock()到state=0(即釋放鎖)為止,其它線程才有機會獲取該鎖。當(dāng)然,釋放鎖之前,A線程自己是可以重復(fù)獲取此鎖的(state會累加),這就是可重入的概念。但要注意,獲取多少次就要釋放多么次,這樣才能保證state是能回到零態(tài)的。

再以CountDownLatch以例,任務(wù)分為N個子線程去執(zhí)行,state也初始化為N(注意N要與線程個數(shù)一致)。這N個子線程是并行執(zhí)行的,每個子線程執(zhí)行完后countDown()一次,state會CAS(Compare and Swap)減1。等到所有子線程都執(zhí)行完后(即state=0),會unpark()主調(diào)用線程,然后主調(diào)用線程就會從await()函數(shù)返回,繼續(xù)后余動作。

一般來說,自定義同步器要么是獨占方法,要么是共享方式,他們也只需實現(xiàn)tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一種即可。但AQS也支持自定義同步器同時實現(xiàn)獨占和共享兩種方式,如ReentrantReadWriteLock。

四、使用demo,使用AQS實現(xiàn)不可重入鎖

實現(xiàn)不可重入鎖需要分兩步來走,一是實現(xiàn)自定義同步器,二是實現(xiàn)自定義鎖

自定義同步器

class MySync extends AbstractQueuedSynchronizer {
        // 嘗試去獲取鎖
        @Override
        protected boolean tryAcquire(int i) {
            // compareAndSetState(0, 1): 嘗試著將state的值從 0改為1
            if (compareAndSetState(0, 1)) {
                // 將持有鎖的線程改為當(dāng)前線程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        // 嘗試去釋放鎖
        @Override
        protected boolean tryRelease(int i) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        // 判斷是否持有獨占鎖
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
        protected Condition newCondition() {
            return new ConditionObject();
        }
    }

自定義鎖

有了自定義同步器,很容易復(fù)用 AQS ,實現(xiàn)一個功能完備的自定義鎖

public class MyLock implements Lock {
    // 自定義同步器 , 實現(xiàn)的是不可重入鎖
    private MySync sync = new MySync();
    @Override
    // 嘗試,不成功,進入等待隊列
    public void lock() {
        sync.acquire(1);
    }
    @Override
    // 嘗試,不成功,進入等待隊列,可打斷
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    @Override
    // 嘗試一次,不成功返回,不進入隊列
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }
    @Override
    // 嘗試,不成功,進入等待隊列,有時限
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }
    @Override
    // 釋放鎖
    public void unlock() {
        sync.release(1);
    }
    @Override
    // 生成條件變量
    public Condition newCondition() {
        return sync.newCondition();
    }
}

測試

@Slf4j(topic = "c.MyLockTest")
public class MyLockTest {
    public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(() -> {
            lock.lock();
            try {
                log.debug("locking...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            } finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        },"t1").start();
        new Thread(() -> {
            lock.lock();
            try {
                log.debug("locking...");
            } finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        },"t2").start();
    }
}

可以看到只有當(dāng)t1線程釋放鎖之后,t2線程才能獲取到鎖

在這里插入圖片描述

五、AQS使用到的幾個框架

1、信號量 Semaphore 允許多個線程同時訪問: synchronized 和 ReentrantLock 都是一次只允許一個線程訪問某個資源,Semaphore(信號量)可以指定多個線程同時訪問某個資源。

2、CountDownLatch (倒計時器) CountDownLatch是一個同步工具類,用來協(xié)調(diào)多個線程之間的同步。這個工具通常用來控制線程等待,它可以讓某一個線程等待直到倒計時結(jié)束,再開始執(zhí)行。

3、CyclicBarrier(循環(huán)柵欄) CountDownLatch 更加復(fù)雜和強大。主要應(yīng)用場景和 CountDownLatch 類似。CyclicBarrier 的字面意思是可循環(huán)使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續(xù)干活。CyclicBarrier默認(rèn)的構(gòu)造方法是 CyclicBarrier(int parties),其參數(shù)表示屏障攔截的線程數(shù)量,每個線程調(diào)用await()方法告訴 CyclicBarrier 我已經(jīng)到達了屏障,然后當(dāng)前線程被阻塞。

到此這篇關(guān)于Java中的AQS框架原理詳解的文章就介紹到這了,更多相關(guān)AQS框架原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java內(nèi)部類原理與用法詳解

    java內(nèi)部類原理與用法詳解

    這篇文章主要介紹了java內(nèi)部類原理與用法,結(jié)合實例形式分析了Java內(nèi)部類的概念、原理、分類及相關(guān)使用技巧,需要的朋友可以參考下
    2019-05-05
  • 消息中間件詳解以及比較選擇

    消息中間件詳解以及比較選擇

    這篇文章主要介紹了消息中間件詳解以及比較選擇,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringBoot實現(xiàn)的Mongodb管理工具使用解析

    SpringBoot實現(xiàn)的Mongodb管理工具使用解析

    這篇文章主要介紹了SpringBoot實現(xiàn)的Mongodb管理工具使用解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • mybatis-plus指定字段模糊查詢的實現(xiàn)方法

    mybatis-plus指定字段模糊查詢的實現(xiàn)方法

    最近項目中使用springboot+mybatis-plus來實現(xiàn),所以下面這篇文章主要給大家介紹了關(guān)于mybatis-plus實現(xiàn)指定字段模糊查詢的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Mybatis全面分頁插件

    Mybatis全面分頁插件

    這篇文章主要為大家詳細(xì)介紹了Mybatis全面分頁插件的使用方法,比較適用于在分頁時候進行攔截,感興趣的小伙伴們可以參考一下
    2016-08-08
  • mybatis plus怎么忽略映射字段

    mybatis plus怎么忽略映射字段

    這篇文章主要介紹了mybatis plus怎么忽略映射字段,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 基于Java實現(xiàn)PPT到PDF的高效轉(zhuǎn)換詳解

    基于Java實現(xiàn)PPT到PDF的高效轉(zhuǎn)換詳解

    在日常開發(fā)中,經(jīng)常會遇到將PPT文檔批量或單文件轉(zhuǎn)換為PDF的需求,本文將詳細(xì)介紹其使用流程、核心代碼與常見問題解決方案,希望對大家有所幫助
    2025-11-11
  • Javafx利用fxml變換場景的實現(xiàn)示例

    Javafx利用fxml變換場景的實現(xiàn)示例

    本文主要介紹了Javafx利用fxml變換場景的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • Springboot設(shè)置統(tǒng)一的返回格式的方法步驟

    Springboot設(shè)置統(tǒng)一的返回格式的方法步驟

    在我們應(yīng)用中我們通常與前端交互使用json格式,設(shè)置統(tǒng)一的返回json 格式是非常必要的,本文主要介紹了Springboot設(shè)置統(tǒng)一的返回格式的方法步驟,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Springboot上傳excel并將表格數(shù)據(jù)導(dǎo)入或更新mySql數(shù)據(jù)庫的過程

    Springboot上傳excel并將表格數(shù)據(jù)導(dǎo)入或更新mySql數(shù)據(jù)庫的過程

    這篇文章主要介紹了Springboot上傳excel并將表格數(shù)據(jù)導(dǎo)入或更新mySql數(shù)據(jù)庫的過程 ,本文以Controller開始,從導(dǎo)入過程開始講述,其中包括字典表的轉(zhuǎn)換,需要的朋友可以參考下
    2018-04-04

最新評論

太保市| 沂水县| 集安市| 洛隆县| 巴中市| 城口县| 桦甸市| 潢川县| 桃源县| 青海省| 五大连池市| 藁城市| 伊金霍洛旗| 长白| 东兰县| 荃湾区| 托里县| 庄河市| 石家庄市| 禹州市| 凤冈县| 南丰县| 扎赉特旗| 高平市| 石嘴山市| 乐安县| 安达市| 北辰区| 丁青县| 基隆市| 五指山市| 托克托县| 土默特右旗| 德格县| 称多县| 浮山县| 鹤壁市| 芷江| 唐海县| 民县| 垦利县|