日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

你真的弄明白了吗?Java并发之AQS详解

發布時間:2025/3/19 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 你真的弄明白了吗?Java并发之AQS详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

你真的弄明白了嗎?Java并發之AQS詳解

帶著問題閱讀

1、什么是AQS,它有什么作用,核心思想是什么

2、AQS中的獨占鎖和共享鎖原理是什么,AQS提供的鎖機制是公平鎖還是非公平鎖

3、AQS在Java中有哪些實現,如何基于AQS實現自己的鎖控制

4、AQS除了提供鎖框架以外還提供了什么能力

AQS介紹
AbstractQueuedSynchronizer(AQS) 提供了一套可用于實現鎖同步機制的框架,不夸張地說, AQS 是 JUC 同步框架的基石。 AQS 通過一個 FIFO 隊列維護線程同步狀態,實現類只需要繼承該類,并重寫指定方法即可實現一套線程同步機制。

AQS 根據資源互斥級別提供了 獨占和共享 兩種資源訪問模式;同時其定義 Condition 結構提供了 wait/signal 等待喚醒機制。在 JUC 中,諸如 ReentrantLock 、 CountDownLatch 等都基于 AQS 實現。

AQS框架
AQS原理

AQS 的原理并不復雜, AQS 維護了一個 volatile int state 變量和一個 CLH(三個人名縮寫)雙向隊列 ,隊列中的節點持有線程引用,每個節點均可通過 getState() 、 setState() 和 compareAndSetState() 對 state 進行修改和訪問。·

當線程獲取鎖時,即試圖對 state 變量做修改,如修改成功則獲取鎖;如修改失敗則包裝為節點掛載到隊列中,等待持有鎖的線程釋放鎖并喚醒隊列中的節點。

AQS模版方法
AQS 內部封裝了隊列維護邏輯,采用模版方法的模式提供實現類以下方法:

tryAcquire(int); // 嘗試獲取獨占鎖,可獲取返回true,否則false tryRelease(int); // 嘗試釋放獨占鎖,可釋放返回true,否則false tryAcquireShared(int); // 嘗試以共享方式獲取鎖,失敗返回負數,只能獲取一次返回0,否則返回個數 tryReleaseShared(int); // 嘗試釋放共享鎖,可獲取返回true,否則false isHeldExclusively(); // 判斷線程是否獨占資源

如實現類只需實現獨占鎖/共享鎖功能,可只實現 tryAcquire/tryRelease 或 tryAcquireShared/tryReleaseShared 。雖然實現 tryAcquire/tryRelease 可自行設定邏輯,但建議使用 state 方法對 state 變量進行操作以實現同步類。

如下是一個簡單的同步鎖實現示例:

public class Mutex extends AbstractQueuedSynchronizer {@Overridepublic boolean tryAcquire(int arg) {return compareAndSetState(0, 1);}@Overridepublic boolean tryRelease(int arg) {return compareAndSetState(1, 0);}public static void main(String[] args) {final Mutex mutex = new Mutex();new Thread(() -> {System.out.println("thread1 acquire mutex");mutex.acquire(1);// 獲取資源后sleep保持try {TimeUnit.SECONDS.sleep(5);} catch(InterruptedException ignore) {}mutex.release(1);System.out.println("thread1 release mutex");}).start();new Thread(() -> {// 保證線程2在線程1啟動后執行try {TimeUnit.SECONDS.sleep(1);} catch(InterruptedException ignore) {}// 等待線程1 sleep結束釋放資源mutex.acquire(1);System.out.println("thread2 acquire mutex");mutex.release(1);}).start()} }

示例代碼簡單通過 AQS 實現一個互斥操作,線程1獲取 mutex 后,線程2的 acquire 陷入阻塞,直到線程1釋放。其中 tryAcquire/acquire/tryRelease/release 的 arg 參數可按實現邏輯自定義傳入值,無具體要求。

@param arg the acquire argument. This value is conveyed to {@link #tryAcquire} but is otherwise uninterpreted and can represent anyting you like.

AQS核心結構
Node
前文提到,在 AQS 中如果線程獲取資源失敗,會包裝成一個節點掛載到 CLH 隊列上, AQS 中定義了 Node 類用于包裝線程。

Node 主要包含5個核心字段:

waitStatus :當前節點狀態,該字段共有5種取值:
CANCELLED = 1 。節點引用線程由于等待超時或被打斷時的狀態。
SIGNAL = -1 。后繼節點線程需要被喚醒時的當前節點狀態。當隊列中加入后繼節點被掛起 (block) 時,其前驅節點會被設置為 SIGNAL 狀態,表示該節點需要被喚醒。
CONDITION = -2 。當節點線程進入 condition 隊列時的狀態。(見 ConditionObject )
PROPAGATE = -3 。僅在釋放共享鎖 releaseShared 時對頭節點使用。(見共享鎖分析)
0 。節點初始化時的狀態。
prev :前驅節點。
next :后繼節點。
thread :引用線程,頭節點不包含線程。
nextWaiter : condition 條件隊列。(見 ConditionObject )
獨占鎖分析
acquire

public final void acquire(int arg) {// tryAcquire需實現類處理// 如獲取資源成功,直接返回if (!tryAcquire(arg) && // 如獲取資源失敗,將線程包裝為Node添加到隊列中阻塞等待acquireQueued(addWaiter(Node.EXCLUSIVE), arg))// 如阻塞線程被打斷selfInterrupt(); }

acquire 核心為 tryAcquire 、 addWaiter 和 acquireQueued 三個函數,其中 tryAcquire 需具體類實現。 每當線程調用 acquire 時都首先會調用 tryAcquire ,失敗后才會掛載到隊列,因此 acquire 實現 默認為非公平鎖 。

addWaiter 將線程包裝為獨占節點,尾插式加入到隊列中,如隊列為空,則會添加一個空的頭節點。值得注意的是 addWaiter 中的 enq 方法,通過 CAS+自旋 的方式處理尾節點添加沖突。


acquireQueue 在線程節點加入隊列后判斷是否可再次嘗試獲取資源,如不能獲取則將其前驅節點標志為 SIGNAL 狀態(表示其需要被 unpark 喚醒)后,則通過 park 進入阻塞狀態。


參照流程圖, acquireQueued 方法核心邏輯為 for(;😉 和 shouldParkAfterFailedAcquire 。 tail 節點默認初始狀態為0,當新節點被掛載到隊列后,將其前驅即原 tail 節點狀態設為 SIGNAL ,表示該節點需要被喚醒,返回 true 后即被 park 陷入阻塞。 for 循環直到節點前驅為 head 后才嘗試進行資源獲取。

release
release 流程較為簡單,嘗試釋放成功后,即從頭結點開始喚醒其后繼節點,如后繼節點被取消,則轉為從尾部開始找阻塞的節點將其喚醒。阻塞節點被喚醒后,即進入 acquireQueued 中的 for(;😉 循環開始新一輪的資源競爭。

共享鎖分析
acquireShared & releaseShared

public final void acquireShared(int arg) {// 負數表示獲取共享鎖失敗,不同于tryAcquire的bool返回if (tryAcquireShared(arg) < 0)doAcquireShared(arg); }public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {doReleaseShared();return true;}return false; }

acquireShared 和 releaseShared 整體流程與獨占鎖類似, tryAcquireShared 獲取失敗后以 Node.SHARED 掛載到隊尾阻塞,直到隊頭節點將其喚醒。在 doAcquireShared 與獨占鎖不同的是,由于共享鎖是可以被多個線程獲取的,因此在首個阻塞節點被喚醒后,會通過 setHeadAndPropagate 傳遞喚醒后續的阻塞節點。

// doAcquireShared核心代碼 final Node node = addWaiter(Node.SHARED); ... for (;;) {final Node p = node.predecessor();if (p == head) {int r = tryAcquireShared(arg);if (r >= 0) {// r>=0 表示獲取鎖成功,調整頭結點并傳遞喚醒setHeadAndPropagate(node, r);}}... }

setHeadAndPropagate 和 doReleaseShared 構成共享鎖喚醒的核心邏輯。

這兩方法的邏輯較為簡單,不再進行展開,主要對 setheadAndPropagate 的多節點喚醒判斷邏輯做出分析。

進入 setHeadAndPropagate ,首先需要明確的是,該函數的傳入參數 propagate 一定是非負數,接下來其喚醒主要為兩個判斷邏輯:

如果 propagate > 0 ,表示存在多個共享鎖可以獲取,可直接進行 doReleaseShared 喚醒阻塞節點。

如果 propagate = 0 ,表示僅當前節點可被喚醒,則有兩種情況:

h == null || h.waitStatus < 0 ,通常情況下 h != null ,現給出 h.waitStatus < 0 的場景。

(h = head) == null || h.waitStatus < 0 的場景執行序列如下:

獨占鎖共享鎖小結

1、獨占鎖共享鎖默認都是非公平獲取策略,可能被插隊。

2、獨占鎖只有一個線程可獲取,其他線程均被阻塞在隊列中;共享鎖可以有多個線程獲取。

3、獨占鎖釋放僅喚醒一個阻塞節點,共享鎖可以根據可用數量,一次喚醒多個阻塞節點

ConditionObject
AQS 中 Node 除了組成阻塞隊列外,還在 ConditionObject 中得到應用, ConditionObject 的核心定義為:

public class ConditionObject implements Condition, java.io.Serializable {... private transient Node firstWaiter;private transient Node lastWaiter;... }

ConditionObject 通過 Node 也構成了一個 FIFO 的隊列,那么 ConditionObject 為 AQS 提供了怎樣的功能呢?

public interface Condition {...void await() throws InterruptedException;void signal();void signalAll();... }

查看 Condition 接口的定義,可以看到其定義的方法與 Object 類的 wait/notify/notifyAll 功能是一致的。

在Synchronized詳解中筆者曾對 ObjectMonitor 做過簡單介紹,其中 ObjectMonitor 包含 _WaitSet 和 _EntryList 兩個隊列,分別用于存儲 wait調用 和 sychronized鎖競爭 時掛起的線程,而 AQS 通過 ConditionObject 同樣也提供了 wait/notify 機制的阻塞隊列。

Condihttps://blog.csdn.net/anlian523/article/details/106319294/tionObject 機制如上圖,在條件隊列中, Node 采用 nextWaiter 組成單向鏈表,當持有鎖的線程發起 condition.await 調用后,會包裝為 Node 掛載到 Condition條件阻塞隊列中 ;當對應 condition.signal 被觸發后,條件阻塞隊列中的節點將被喚醒并掛載到 鎖阻塞隊列 中。 ConditionObject 的隊列邏輯與前述的 acquire/release 大同小異,不再贅述。

多多支持Remi醬吧!
愛你哦~

文章來源:https://www.tuicool.com/articles/iYzUfa2

總結

以上是生活随笔為你收集整理的你真的弄明白了吗?Java并发之AQS详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天摸天天舔天天操 | 99久久精品免费看国产 | 三级视频国产 | 国产精品久久久久久久一区二区 | 亚洲成人资源 | 综合视频一区 | 伊人伊人伊人伊人 | 久久1024| 色婷婷综合成人av | 国产精品久久久久久久久久直播 | 精品免费国产 | 可以免费看黄的网站 | 麻豆国产尤物av尤物在线观看 | 少妇一级视频 | 国产美女免费 | 国产又大又粗又硬 | 二区在线观看 | 任你操精品 | 日韩欧美高清在线视频 | 欧美日韩人妻精品一区二区 | 高潮毛片无遮挡高清免费 | 肮脏的交易在线观看 | 国产精品成人一区二区网站软件 | av狠狠 | 京香julia在线观看 | 日韩123区 | 欧美不卡一区 | 日韩欧美国产另类 | 蜜桃久久av | 伊人色综合久久久 | 国产九色视频 | 欧美日韩亚洲精品一区二区 | 色婷婷一区 | 欧美亚洲国产一区 | 波多野在线播放 | 精品麻豆 | 国产xx在线观看 | a天堂中文在线 | 亚洲天堂黄 | 91精品久久香蕉国产线看观看 | 动漫美女被吸奶 | 亚洲丁香花色 | 国产成人无码一区二区在线观看 | 欧美激情影院 | 8050午夜一级毛片久久亚洲欧 | 久久免费看少妇高潮 | www.av免费 | 青青草免费观看 | 老头糟蹋新婚少妇系列小说 | 国产91专区 | 人妻少妇偷人精品无码 | 沈樵精品国产成av片 | 亚洲天堂中文 | 天天拍天天射 | 欧美人与禽zoz0性3d | 在线观看免费黄视频 | 免费看h网站 | 97超碰自拍| 色av一区 | 一区二区三区四区五区在线视频 | 国产精品无码一区二区三区免费 | 黄色片久久久久 | av片免费 | 噜噜噜精品欧美成人 | 精品人人妻人人澡人人爽牛牛 | 日本欧美成人 | 在线免费看黄av | 亚州久久久 | 成人美女在线 | 中文字幕在线一 | jizz毛片| 亚洲视频精品一区 | 久久精品这里只有精品 | 熟女高潮一区二区三区视频 | 欧美国产一级 | 樱桃视频一区二区三区 | 综合网伊人 | 亚洲一二三视频 | 国产妻精品一区二区在线 | 少妇aaaa | 九九99久久 | 国产精品理论片 | 亚洲中文字幕在线观看 | 精品三区 | 久久久久久无码精品人妻一区二区 | 亚洲人成一区 | 少妇精品久久久一区二区三区 | av免费观看大全 | 欧美日本在线视频 | 日本一级片在线观看 | 免费看操片 | 97色爱| 性欧美17一18内谢 | 麻豆精品免费观看 | 欧美资源站 | 污污视频在线播放 | 亚洲一区二区三区久久久 | 老司机午夜剧场 | 小敏的受孕日记h |