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

Java中的AQS入門攻略

 更新時間:2025年10月22日 11:17:26   作者:程序員小假  
AQS(AbstractQueuedSynchronizer)是JUC包中用于構建鎖和同步器的核心框架,它通過volatile的state變量和FIFO隊列實現(xiàn)線程同步,簡化了同步工具的開發(fā),并支持獨占與共享兩種模式,本文介紹Java中的AQS是什么,感興趣的朋友跟隨小編一起看看吧

一、AQS 是什么?

AQS,全稱 AbstractQueuedSynchronizer,即抽象隊列同步器。

  • 抽象:它是一個抽象類,本身不能直接實例化,需要子類去繼承它,并實現(xiàn)其保護方法來管理同步狀態(tài)。
  • 隊列:它內部維護了一個先進先出(FIFO)的等待隊列,用于存放那些沒有搶到鎖的線程。
  • 同步器:它是構建鎖和其他同步組件(如 Semaphore、CountDownLatch 等)的基礎框架。

核心思想:
AQS 使用一個整型的 volatile 變量(state 來表示同步狀態(tài)(例如,鎖被重入的次數(shù)、許可的數(shù)量等),并通過一個內置的 FIFO 隊列來完成資源獲取線程的排隊工作。

設計模式:
AQS 是 模板方法模式 的經典應用。父類(AQS)定義了骨架和核心算法,而將一些關鍵的操作以 protected 方法的形式留給子類去實現(xiàn)。這樣,實現(xiàn)一個自定義同步器只需要關注如何管理 state 狀態(tài)即可,至于線程的排隊、等待、喚醒等復雜操作,AQS 已經幫我們完成了。

二、AQS 的核心結構

AQS 的核心可以概括為三部分:同步狀態(tài)(state)等待隊列 和 條件隊列。

1. 同步狀態(tài)(State)

這是一個 volatile int 類型的變量,是 AQS 的靈魂。

private volatile int state;

它的具體含義由子類決定,非常靈活:

  • 在 ReentrantLock 中,state 表示鎖被同一個線程重復獲取的次數(shù)。state=0 表示鎖空閑,state=1 表示鎖被占用,state>1 表示鎖被重入。
  • 在 Semaphore 中,state 表示當前可用的許可數(shù)量。
  • 在 CountDownLatch 中,state 表示計數(shù)器當前的值。

對 state 的操作是原子的,通過 getState()setState(int newState)compareAndSetState(int expect, int update) 等方法進行。

2. 等待隊列(CLH 隊列的變體)

這是一個雙向鏈表,是 AQS 實現(xiàn)阻塞鎖的關鍵。當線程請求共享資源失敗時,AQS 會將當前線程以及等待狀態(tài)等信息構造成一個節(jié)點(Node) 并將其加入隊列的尾部,同時阻塞該線程。

  • 頭節(jié)點(Head):指向獲取到資源的線程所在的節(jié)點。頭節(jié)點不持有線程,是一個“虛節(jié)點”。
  • 尾節(jié)點(Tail):指向隊列中最后一個節(jié)點。

當一個線程釋放資源時,它會喚醒后繼節(jié)點,后繼節(jié)點成功獲取資源后,會將自己設置為新的頭節(jié)點。

主要原理圖如下:

AQS 使用一個 Volatile 的 int 類型的成員變量來表示同步狀態(tài),通過內置的 FIFO 隊列來完成資源獲取的排隊工作,通過 CAS 完成對 State 值的修改。

3. 條件隊列(Condition Object)

AQS 內部類 ConditionObject 實現(xiàn)了 Condition 接口,用于支持 await/signal 模式的線程間協(xié)作。每個 ConditionObject 對象都維護了一個自己的單向鏈表(條件隊列)

  • 當線程調用 Condition.await() 時,會釋放鎖,并將當前線程構造成節(jié)點加入條件隊列,然后阻塞。
  • 當線程調用 Condition.signal() 時,會將條件隊列中的第一個等待節(jié)點轉移到 AQS 的等待隊列中,等待重新獲取鎖。

注意:一個 AQS 實例可以對應多個 Condition 對象(即多個條件隊列),但只有一個等待隊列。

三、AQS 的設計與關鍵方法

AQS 將資源獲取的方式分為兩種:

  • 獨占模式(Exclusive):一次只有一個線程能執(zhí)行,如 ReentrantLock。
  • 共享模式(Shared):多個線程可以同時執(zhí)行,如 Semaphore、CountDownLatch。

AQS 提供了頂層的入隊和出隊邏輯,而將嘗試獲取資源嘗試釋放資源的具體策略留給了子類。

需要子類重寫的關鍵方法(Protected)

這些方法在 AQS 中是 protected 的,默認拋出 UnsupportedOperationException。

獨占模式:

  • boolean tryAcquire(int arg):嘗試以獨占方式獲取資源。成功返回 true,失敗返回 false。
  • boolean tryRelease(int arg):嘗試以獨占方式釋放資源。成功返回 true,失敗返回 false。

共享模式:

  • int tryAcquireShared(int arg):嘗試以共享方式獲取資源。負數(shù)表示失?。? 表示成功,但后續(xù)共享獲取可能失?。徽龜?shù)表示成功,且后續(xù)共享獲取可能成功。
  • boolean tryReleaseShared(int arg):嘗試以共享方式釋放資源。

其他:

  • boolean isHeldExclusively():當前同步器是否在獨占模式下被線程占用。在 Condition 相關操作中會用到。

供外部調用的重要方法(Public)

這些是模板方法,子類一般不重寫,使用者(或子類)直接調用。

獨占模式:

  • void acquire(int arg):以獨占模式獲取資源,忽略中斷。如果獲取失敗,會進入等待隊列。
  • void acquireInterruptibly(int arg):同上,但響應中斷。
  • boolean tryAcquireNanos(int arg, long nanosTimeout):在 acquireInterruptibly 基礎上增加了超時限制。
  • boolean release(int arg):以獨占模式釋放資源。

共享模式:

  • void acquireShared(int arg):以共享模式獲取資源。
  • void acquireSharedInterruptibly(int arg):響應中斷的共享獲取。
  • boolean tryAcquireSharedNanos(int arg, long nanosTimeout):帶超時的共享獲取。
  • boolean releaseShared(int arg):以共享模式釋放資源。

四、源碼級工作流程解析(以acquire為例)

我們來看一下最核心的 acquire 方法,它展示了 AQS 的完整工作流程:

public final void acquire(int arg) {
    if (!tryAcquire(arg) && // 1. 嘗試直接獲取資源(子類實現(xiàn))
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 2. 獲取失敗,則加入隊列;3. 在隊列中自旋/阻塞等待
        selfInterrupt(); // 如果在等待過程中被中斷,補上中斷標記
}
  • tryAcquire(arg)
    • 這是子類實現(xiàn)的方法。比如在 ReentrantLock 的非公平鎖實現(xiàn)中,它會直接嘗試使用 CAS 修改 state,如果成功,就將當前線程設置為獨占線程。
    • 如果 tryAcquire 成功,整個 acquire 方法就結束了,線程繼續(xù)執(zhí)行。
    • 如果失敗,進入下一步。
  • addWaiter(Node.EXCLUSIVE)
    • 創(chuàng)建一個代表當前線程的 Node 節(jié)點,模式為獨占模式(Node.EXCLUSIVE)。
    • 通過 CAS 操作,快速地將這個新節(jié)點設置為尾節(jié)點。如果失敗,則進入 enq(node) 方法,通過自旋 CAS 的方式確保節(jié)點被成功添加到隊列尾部。
  • acquireQueued(final Node node, int arg)
    • 這是核心中的核心。節(jié)點入隊后,會在這個方法里進行自旋(循環(huán))等待。
    • 在循環(huán)中,它會檢查自己的前驅節(jié)點是不是頭節(jié)點(p == head)。如果是,說明自己是隊列中第一個等待的線程,會再次調用 tryAcquire 嘗試獲取資源(因為此時鎖可能剛好被釋放了,這是一個避免不必要的線程掛起、提高性能的優(yōu)化)。
    • 如果獲取成功,就將自己設為新的頭節(jié)點,然后返回。
    • 如果前驅不是頭節(jié)點,或者再次嘗試獲取失敗,則會調用 shouldParkAfterFailedAcquire 方法,檢查并更新前驅節(jié)點的狀態(tài)(比如將其 waitStatus 設置為 SIGNAL,表示“當你釋放鎖時,需要喚醒我”)。
    • 如果一切就緒,就調用 parkAndCheckInterrupt() 方法,使用 LockSupport.park(this) 阻塞(掛起)當前線程。
    • 當線程被喚醒后(通常是由前驅節(jié)點釋放鎖時 unpark 的),會再次檢查自己是否是頭節(jié)點的后繼,并重復上述自旋過程,直到成功獲取資源。
  • selfInterrupt()
    • 如果在等待過程中線程被中斷,acquireQueued 方法會返回 true,這里會調用 selfInterrupt 補上中斷標志,因為 AQS 在 acquire 過程中是忽略中斷的。

釋放流程(release)相對簡單:

public final boolean release(int arg) {
    if (tryRelease(arg)) { // 1. 子類嘗試釋放資源
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h); // 2. 喚醒后繼節(jié)點
        return true;
    }
    return false;
}

unparkSuccessor 會找到隊列中第一個需要喚醒的線程(通常是頭節(jié)點的下一個有效節(jié)點),然后調用 LockSupport.unpark(s.thread) 將其喚醒。

五、AQS 的應用舉例

AQS 是 JUC 包的基石,幾乎所有的同步工具都基于它:

  • ReentrantLock:使用 AQS 的獨占模式,state 表示重入次數(shù)。
  • ReentrantReadWriteLock:讀寫鎖。AQS 的 state 高16位表示讀鎖狀態(tài),低16位表示寫鎖狀態(tài)。
  • Semaphore:使用 AQS 的共享模式,state 表示可用許可數(shù)。
  • CountDownLatch:使用 AQS 的共享模式,state 表示計數(shù)器值。countDown() 是 releaseSharedawait() 是 acquireShared。
  • ThreadPoolExecutor:其內部的工作線程 Worker 類,也繼承了 AQS,用于實現(xiàn)獨占鎖,來判斷線程是否空閑。

六、總結

AQS 的核心貢獻在于,它提供了一個強大的框架,將復雜的線程排隊、阻塞、喚醒等底層操作封裝起來,讓同步器的開發(fā)者只需要關注一個核心問題:如何管理那個 state 變量。

它的優(yōu)點:

  • 極大地降低了構建鎖和同步器的復雜度。
  • 性能高效:通過自旋、CAS 等無鎖編程技術,減少了線程上下文切換的開銷。
  • 靈活強大:通過兩種模式的區(qū)分,可以構建出各種復雜的同步工具。

到此這篇關于Java中的AQS入門攻略的文章就介紹到這了,更多相關java aqs是什么內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java 線程池_動力節(jié)點Java學院整理

    Java 線程池_動力節(jié)點Java學院整理

    系統(tǒng)啟動一個新線程的成本是比較高的,因為它涉及到與操作系統(tǒng)的交互。在這種情況下,使用線程池可以很好的提供性能,尤其是當程序中需要創(chuàng)建大量生存期很短暫的線程時,更應該考慮使用線程池
    2017-05-05
  • Springboot引入多個yml方法(多種方案)

    Springboot引入多個yml方法(多種方案)

    SpringBoot默認加載的是application.yml文件,所以想要引入其他配置的yml文件,就要在application.yml中激活該文件這篇文章主要介紹了Springboot引入多個yml方法,需要的朋友可以參考下
    2019-10-10
  • IDEA中用maven連接數(shù)據(jù)庫的教程

    IDEA中用maven連接數(shù)據(jù)庫的教程

    這篇文章主要介紹了IDEA中用maven連接數(shù)據(jù)庫的教程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • java??常見位邏輯運算符梳理

    java??常見位邏輯運算符梳理

    這篇文章主要介紹了java常見位邏輯運算符梳理,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,感興趣的小伙伴可以參一下下面文章詳細內容
    2022-08-08
  • 深入了解Java SpringBoot自動裝配原理

    深入了解Java SpringBoot自動裝配原理

    在使用springboot時,很多配置我們都沒有做,都是springboot在幫我們完成,這很大一部分歸功于springboot自動裝配。本文將詳細為大家講解SpringBoot的自動裝配原理,需要的可以參考一下
    2022-03-03
  • Java Volatile關鍵字同步機制詳解

    Java Volatile關鍵字同步機制詳解

    這篇文章主要介紹了Java Volatile關鍵字同步機制詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • 詳解Java線程-守護線程與用戶線程

    詳解Java線程-守護線程與用戶線程

    這篇文章主要介紹了Java守護線程與用戶線程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Hibernate命名策略詳解

    Hibernate命名策略詳解

    本文主要介紹了Hibernate命名策略。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • Java中RocketMQ的流量削峰詳解

    Java中RocketMQ的流量削峰詳解

    這篇文章主要介紹了Java中RocketMQ的流量削峰詳解,MQ的主要特點為解耦、異步、削峰,該文章主要記錄與分享個人在實際項目中的RocketMQ削峰用法,用于減少數(shù)據(jù)庫壓力的業(yè)務場景,需要的朋友可以參考下
    2023-09-09
  • 一篇文章弄懂Mybatis中#和$的區(qū)別

    一篇文章弄懂Mybatis中#和$的區(qū)別

    mybatis為我們提供了兩種支持動態(tài)sql的語法#{}以及${},兩者都是動態(tài)的向sql語句中傳入需要的參數(shù),下面這篇文章主要給大家介紹了如何通過一篇文章弄懂Mybatis中#和$區(qū)別的相關資料,需要的朋友可以參考下
    2021-12-12

最新評論

阿合奇县| 萝北县| 任丘市| 丹棱县| 南投县| 繁昌县| 镇雄县| 馆陶县| 酉阳| 长丰县| 静乐县| 乌兰浩特市| 汝州市| 孝昌县| 东宁县| 承德县| 洪洞县| 富民县| 大冶市| 通州区| 贞丰县| 涟水县| 门头沟区| 历史| 榕江县| 鸡东县| 龙山县| 盘锦市| 资兴市| 霍林郭勒市| 文登市| 密山市| 监利县| 玛多县| 宝清县| 聊城市| 廉江市| 绵竹市| 榆树市| 潮安县| 若尔盖县|