国产一区在线不卡_国产精品天天摸av网_日韩精品中文字幕第1页_国产精品无码专区在线观看

latch和lock的區(qū)別_兒童安全座椅latch接口

首頁 > 汽車 > 車市行情 > 正文

latch和lock的區(qū)別_兒童安全座椅latch接口

前言

AbstractQueuedSynchronizer(AQS)是 Java 并發(fā)編程中繞不過去的一道坎,JUC 并發(fā)包下的 Lock、Semaphore、ReentrantLock 等都是基于 AQS 實(shí)現(xiàn)的。AQS 是一個抽象的同步框架,提供了原子性管理同步狀態(tài),基于阻塞隊(duì)列模型實(shí)現(xiàn)阻塞和喚醒等待線程的功能

文章從 ReentrantLock 加鎖、解鎖應(yīng)用 API 入手,逐步講解 AQS 對應(yīng)源碼以及相關(guān)隱含流程

列出本篇文章大綱以及相關(guān)知識點(diǎn),方便大家更好的理解

latch和lock的區(qū)別_兒童安全座椅latch接口

什么是 ReentrantLock

ReentrantLock 翻譯為 可重入鎖,指的是一個線程能夠?qū)?臨界區(qū)共享資源進(jìn)行重復(fù)加鎖

確保線程安全最常見的做法是利用鎖機(jī)制(Lock、sychronized)來對 共享數(shù)據(jù)做互斥同步,這樣在同一個時刻,只有 一個線程可以執(zhí)行某個方法或者某個代碼塊,那么操作必然是 原子性的,線程安全的

這里就有個疑問,因?yàn)?JDK 中關(guān)鍵字 synchronized 也能同時支持原子性以及線程安全

有了 synchronized 關(guān)鍵字后為什么還需要 ReentrantLock?

為了大家更好的掌握 ReentrantLock 源碼,這里列出兩種鎖之間的區(qū)別

通過以上六個維度比對,可以看出 ReentrantLock 是要比 synchronized 靈活以及支持功能更豐富

什么是 AQS

AQS( AbstractQueuedSynchronizer )是一個用來構(gòu)建鎖和同步器的抽象框架,只需要繼承 AQS 就可以很方便的實(shí)現(xiàn)我們自定義的多線程同步器、鎖

如圖所示,在 java.util.concurrent 包下相關(guān)鎖、同步器(常用的有 ReentrantLock、 ReadWriteLock、CountDownLatch…)都是基于 AQS 來實(shí)現(xiàn)

AQS 是典型的模板方法設(shè)計模式,父類(AQS)定義好骨架和內(nèi)部操作細(xì)節(jié),具體規(guī)則由子類去實(shí)現(xiàn)

AQS 核心原理

如果被請求的共享資源未被占用,將當(dāng)前請求資源的線程設(shè)置為獨(dú)占線程,并將共享資源設(shè)置為鎖定狀態(tài)

AQS 使用一個 Volatile 修飾的 int 類型的成員變量 State 來表示同步狀態(tài),修改同步狀態(tài)成功即為獲得鎖

Volatile 保證了變量在多線程之間的可見性,修改 State 值時通過 CAS 機(jī)制來保證修改的原子性

如果共享資源被占用,需要一定的阻塞等待喚醒機(jī)制來保證鎖的分配,AQS 中會將競爭共享資源失敗的線程添加到一個變體的 CLH 隊(duì)列中

關(guān)于支撐 AQS 特性的重要方法及屬性如下:

CLH 隊(duì)列

既然是 AQS 中使用的是 CLH 變體隊(duì)列,我們先來了解下 CLH 隊(duì)列是什么

CLH:Craig、Landin and Hagersten 隊(duì)列,是 單向鏈表實(shí)現(xiàn)的隊(duì)列。申請線程只在本地變量上自旋,它不斷輪詢前驅(qū)的狀態(tài),如果發(fā)現(xiàn) 前驅(qū)節(jié)點(diǎn)釋放了鎖就結(jié)束自旋

通過對 CLH 隊(duì)列的說明,可以得出以下結(jié)論

  1. CLH 隊(duì)列是一個單向鏈表,保持 FIFO 先進(jìn)先出的隊(duì)列特性
  2. 通過 tail 尾節(jié)點(diǎn)(原子引用)來構(gòu)建隊(duì)列,總是指向最后一個節(jié)點(diǎn)
  3. 未獲得鎖節(jié)點(diǎn)會進(jìn)行自旋,而不是切換線程狀態(tài)
  4. 并發(fā)高時性能較差,因?yàn)槲传@得鎖節(jié)點(diǎn)不斷輪訓(xùn)前驅(qū)節(jié)點(diǎn)的狀態(tài)來查看是否獲得鎖

AQS 中的隊(duì)列是 CLH 變體的虛擬雙向隊(duì)列,通過將每條請求共享資源的線程封裝成一個節(jié)點(diǎn)來實(shí)現(xiàn)鎖的分配

相比于 CLH 隊(duì)列而言,AQS 中的 CLH 變體等待隊(duì)列擁有以下特性

  1. AQS 中隊(duì)列是個雙向鏈表,也是 FIFO 先進(jìn)先出的特性
  2. 通過 Head、Tail 頭尾兩個節(jié)點(diǎn)來組成隊(duì)列結(jié)構(gòu),通過 volatile 修飾保證可見性
  3. Head 指向節(jié)點(diǎn)為已獲得鎖的節(jié)點(diǎn),是一個虛擬節(jié)點(diǎn),節(jié)點(diǎn)本身不持有具體線程
  4. 獲取不到同步狀態(tài),會將節(jié)點(diǎn)進(jìn)行自旋獲取鎖,自旋一定次數(shù)失敗后會將線程阻塞,相對于 CLH 隊(duì)列性能較好
認(rèn)識 AOS

抽象類 AQS 同樣繼承自抽象類 AOS(AbstractOwnableSynchronizer)

AOS 內(nèi)部只有一個 Thread 類型的變量,提供了獲取和設(shè)置當(dāng)前獨(dú)占鎖線程的方法

主要作用是 記錄當(dāng)前占用獨(dú)占鎖(互斥鎖)的線程實(shí)例

為什么要掌握 AQS

如何能夠體現(xiàn)程序員的水平,那就是掌握大多數(shù)人所不掌握的技術(shù),這也是為什么面試時 AQS 高頻出現(xiàn)的原因,因?yàn)樗缓唵?/span>

最初接觸 ReentrantLock 以及 AQS 的時候,看到源碼就是一頭霧水,Debug 跟著跟著就 迷失了自己,相信這也是大多數(shù)人的反應(yīng)

正是因?yàn)榻?jīng)歷過,所以才能從小白的心理上出發(fā),把其中的知識點(diǎn)能夠盡數(shù)梳理

作者寫的很用心,看過這篇文章的小伙伴,不敢保證百分百理解 AQS 和 ReentrantLock 的原理,但是一定會有所收獲

獨(dú)占加鎖源碼解析什么是獨(dú)占鎖

獨(dú)占鎖也叫排它鎖,是指該鎖一次只能被一個線程所持有,如果別的線程想要獲取鎖,只有等到持有鎖線程釋放

獲得排它鎖的線程即能讀數(shù)據(jù)又能修改數(shù)據(jù),與之對立的就是共享鎖

共享鎖是指該鎖可被多個線程所持有。如果線程T對數(shù)據(jù)A加上共享鎖后,則其他線程只能對A再加共享鎖,不能加排它鎖

獲得共享鎖的線程只能讀數(shù)據(jù),不能修改數(shù)據(jù)

獨(dú)占鎖加鎖

ReentrantLock 就是獨(dú)占鎖的一種實(shí)現(xiàn)方式,接下來看代碼中如何使用 ReentrantLock 完成獨(dú)占式加鎖業(yè)務(wù)邏輯

new ReentrantLock() 構(gòu)造函數(shù)默認(rèn)創(chuàng)建的是非公平鎖 NonfairSync

同時也可以在創(chuàng)建鎖構(gòu)造函數(shù)中傳入具體參數(shù)創(chuàng)建公平鎖 FairSync

FairSync、NonfairSync 代表公平鎖和非公平鎖,兩者都是 ReentrantLock 靜態(tài)內(nèi)部類,只不過實(shí)現(xiàn)不同鎖語義

公平鎖 FairSync

  1. 公平鎖是指多個線程按照申請鎖的順序來獲取鎖,線程直接進(jìn)入隊(duì)列中排隊(duì),隊(duì)列中的第一個線程才能獲得鎖
  2. 公平鎖的優(yōu)點(diǎn)是等待鎖的線程不會餓死。缺點(diǎn)是整體吞吐效率相對非公平鎖要低,等待隊(duì)列中除第一個線程以外的所有線程都會阻塞,CPU 喚醒阻塞線程的開銷比非公平鎖大

非公平鎖 NonfairSync

  1. 非公平鎖是多個線程加鎖時直接嘗試獲取鎖,獲取不到才會到等待隊(duì)列的隊(duì)尾等待。但如果此時鎖剛好可用,那么這個線程可以無需阻塞直接獲取到鎖
  2. 非公平鎖的優(yōu)點(diǎn)是可以減少喚起線程的開銷,整體的吞吐效率高,因?yàn)榫€程有幾率不阻塞直接獲得鎖,CPU 不必喚醒所有線程。缺點(diǎn)是處于等待隊(duì)列中的線程可能會餓死,或者等很久才會獲得鎖

兩者的都繼承自 ReentrantLock 靜態(tài)抽象內(nèi)部類 Sync,Sync 類繼承自 AQS,這里就有個疑問

這些鎖都沒有直接繼承 AQS,而是定義了一個 Sync 類去繼承 AQS,為什么要這樣呢?

因?yàn)?鎖面向的是使用用戶同步器面向的則是線程控制,那么在鎖的實(shí)現(xiàn)中聚合同步器而不是直接繼承 AQS 就可以很好的 隔離二者所關(guān)注的事情

通過對不同鎖種類的講解以及 ReentrantLock 內(nèi)部結(jié)構(gòu)的解析,根據(jù)上下級關(guān)系繼承圖,加深其理解

這里以非公平鎖舉例,查看加鎖的具體過程,詳細(xì)信息下文會詳細(xì)說明

看一下非公平鎖加鎖方法 lock 內(nèi)部怎么做的

Sync#lock 為抽象方法,最終會調(diào)用其子類非公平鎖的方法 lock

非公平加鎖方法有兩個邏輯

  1. 通過比較并替換 State(同步狀態(tài))成功與否決定是否獲得鎖,設(shè)置 State 為 1表示成功獲取鎖,并將當(dāng)前線程設(shè)置為獨(dú)占線程
  2. 修改 State 值失敗則進(jìn)入嘗試獲取鎖流程,acquire 方法為 AQS 提供的方法

compareAndSetState 以 CAS 比較并替換的方式將 State 值設(shè)置為 1,表示同步狀態(tài)被占用

setExclusiveOwnerThread 設(shè)置當(dāng)前線程為獨(dú)占鎖擁有線程

acquire 對整個 AQS 做到了承上啟下的作用,通過 tryAcquire 模版方法進(jìn)行嘗試獲取鎖,獲取鎖失敗包裝當(dāng)前線程為 Node 節(jié)點(diǎn)加入等待隊(duì)列排隊(duì)

tryAcquire 是 AQS 中抽象模版方法,但是內(nèi)部會有默認(rèn)實(shí)現(xiàn),雖然默認(rèn)的方法內(nèi)部拋出異常,為什么不直接定義為抽象方法呢?

因?yàn)?AQS 不只是對獨(dú)占鎖實(shí)現(xiàn)了抽象,同時還包括共享鎖;不同鎖定義了不同類別的方法,共享鎖就不需要 tryAcquire,如果定義為抽象方法,繼承 AQS 子類都需要實(shí)現(xiàn)該方法

NonfairSync 類中有 tryAcquire 重寫方法,繼續(xù)查看具體如何進(jìn)行非公平方式獲取鎖

由于 tryAcquire 做了取反,如果設(shè)置 state 失敗并且獨(dú)占鎖線程不是自己本身返回 false,通過取反會進(jìn)入接下來的流程

Node 入隊(duì)流程

嘗試獲得鎖失敗,接下來會將線程組裝成為 Node 進(jìn)行入隊(duì)流程

Node 是 AQS 中最基本的數(shù)據(jù)結(jié)構(gòu),也是 CLH 變體隊(duì)列中的節(jié)點(diǎn),Node 有 SHARED(共享)、EXCLUSIVE(獨(dú)占) 兩種模式,文章主要介紹 EXCLUSIVE 模式,不相關(guān)的屬性和方法不予介紹

下面列出關(guān)于 Node EXCLUSIVE 模式的一些關(guān)鍵方法以及狀態(tài)信息

Node 中獨(dú)占鎖相關(guān)的 waitStatus 屬性分別有以下幾種狀態(tài)

介紹完 Node 相關(guān)基礎(chǔ)知識,看一下請求鎖線程如何被包裝為 Node,又是如何初始化入隊(duì)的

pred 為隊(duì)列的尾節(jié)點(diǎn),根據(jù)尾節(jié)點(diǎn)是否為空會執(zhí)行對應(yīng)流程

  1. 尾節(jié)點(diǎn)不為空,證明隊(duì)列已被初始化,那么需要將對應(yīng)的 node(當(dāng)前線程)設(shè)置為新的尾節(jié)點(diǎn),也就是入隊(duì)操作;將 node 節(jié)點(diǎn)的前驅(qū)指針指向 pred(尾節(jié)點(diǎn)),并將 node 通過 CAS 方式設(shè)置為 AQS 等待隊(duì)列的尾節(jié)點(diǎn),替換成功后將原來的尾節(jié)點(diǎn)后繼指針指向新的尾節(jié)點(diǎn)
  2. 尾節(jié)點(diǎn)為空,證明還沒有初始化隊(duì)列,執(zhí)行 enq 方法進(jìn)行初始化隊(duì)列

enq 方法執(zhí)行初始化隊(duì)列操作,等待隊(duì)列中虛擬化的頭節(jié)點(diǎn)也是在這里產(chǎn)生

執(zhí)行 enq 方法的前提就是隊(duì)列尾節(jié)點(diǎn)為空,為什么還要再判斷尾節(jié)點(diǎn)是否為空?

因?yàn)?enq 方法中是一個死循環(huán),循環(huán)過程中 t 的值是不固定的。假如執(zhí)行 enq 方法時隊(duì)列為空,for 循環(huán)會執(zhí)行兩遍不同的處理邏輯

  1. 尾節(jié)點(diǎn)為空,虛擬化出一個新的 Node 頭節(jié)點(diǎn),這時隊(duì)列中只有一個元素,為了保證 AQS 隊(duì)列結(jié)構(gòu)的完整性,會將尾節(jié)點(diǎn)指向頭節(jié)點(diǎn),第一遍循環(huán)結(jié)束
  2. 第二遍不滿足尾節(jié)點(diǎn)為空條件,執(zhí)行 else 語句塊,node 節(jié)點(diǎn)前驅(qū)指針指向尾節(jié)點(diǎn),并將 node 通過 CAS 設(shè)置為新的尾節(jié)點(diǎn),成功后設(shè)置原尾節(jié)點(diǎn)的后繼指針指向 node,至此入隊(duì)成功。返回的 t 無意義,只是為了終止死循環(huán)

畫兩張圖來理解 enq 方法整體初始化 AQS 隊(duì)列流程,假設(shè)T1、T2兩個線程爭取鎖,T1成功獲得鎖,T2進(jìn)行入隊(duì)操作

  1. T2進(jìn)行入隊(duì)操作,循環(huán)第一遍,尾節(jié)點(diǎn)為空。開始初始化頭節(jié)點(diǎn),并將尾節(jié)點(diǎn)指向頭節(jié)點(diǎn),最終隊(duì)列形式是這樣紙滴
  1. 循環(huán)第二遍,需要將 node 設(shè)置為新的尾節(jié)點(diǎn)。邏輯如下:尾節(jié)點(diǎn)不為空,設(shè)置 node 前驅(qū)指針指向尾節(jié)點(diǎn),并將 node 設(shè)置為尾節(jié)點(diǎn),原尾節(jié)點(diǎn) next 指針指向 node

addWaiter 方法就是為了讓 Node 入隊(duì),并且維護(hù)出一個雙向隊(duì)列模型

入隊(duì)執(zhí)行成功后,會在 acquireQueued 再次嘗試競爭鎖,競爭失敗后會將線程阻塞

acquireQueued 方法會嘗試自旋獲取鎖,獲取失敗對當(dāng)前線程實(shí)施阻塞流程,這也是為了避免無意義的自旋,對比 CLH 隊(duì)列性能優(yōu)化的體現(xiàn)

通過 node.predecessor() 獲取節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn),前驅(qū)節(jié)點(diǎn)為空拋出空指針異常

獲取到前驅(qū)節(jié)點(diǎn)后進(jìn)行兩步邏輯判斷

  1. 判斷前驅(qū)節(jié)點(diǎn) p 是否為頭節(jié)點(diǎn),為 true 進(jìn)行嘗試獲取鎖,獲取鎖成功設(shè)置當(dāng)前節(jié)點(diǎn)為新的頭節(jié)點(diǎn),并將原頭節(jié)點(diǎn)的后驅(qū)指針設(shè)為空
  2. 前驅(qū)節(jié)點(diǎn)不是頭節(jié)點(diǎn)或者嘗試加鎖失敗,執(zhí)行線程休眠阻塞操作

如果 node 獲得鎖后,setHead 將節(jié)點(diǎn)設(shè)置為隊(duì)列頭,從而實(shí)現(xiàn)出隊(duì)效果,出于 GC 的考慮,清空未使用的數(shù)據(jù)

shouldParkAfterFailedAcquire 需要重點(diǎn)關(guān)注下,流程相對比較難理解

ws 表示為當(dāng)前申請鎖節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)的等待狀態(tài),代碼中包含三個邏輯,分別是:

  1. ws == Node.SIGNAL,表示需要將申請鎖節(jié)點(diǎn)進(jìn)行阻塞
  2. ws > 0,表示等待隊(duì)列中包含被取消節(jié)點(diǎn),需要調(diào)整隊(duì)列
  3. 如果 ws == Node.SIGNAL || ws >0 都為 false,使用 CAS 的方式將前驅(qū)節(jié)點(diǎn)等待狀態(tài)設(shè)置為 Node.SIGNAL

設(shè)置當(dāng)前節(jié)點(diǎn)的前置節(jié)點(diǎn)等待狀態(tài)為 Node.SIGNAL,表示當(dāng)前節(jié)點(diǎn)獲取鎖失敗,需要進(jìn)行阻塞操作

還是通過幾張圖來理解流程,假設(shè)此時 T1、T2 線程來爭奪鎖

T1 線程獲得鎖,T2 進(jìn)入 AQS 等待隊(duì)列排隊(duì),并通過 CAS 將 T2 節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)等待狀態(tài)置為 SIGNAL

執(zhí)行切換前驅(qū)節(jié)點(diǎn)等待狀態(tài)后返回 false,繼續(xù)進(jìn)行循環(huán)嘗試獲取同步狀態(tài)

這一步操作保證了線程能進(jìn)行多次重試,盡量避免線程狀態(tài)切換

如果 T1 線程沒有釋放鎖,T2 線程第二次執(zhí)行到 shouldParkAfterFailedAcquire 方法,因?yàn)榍膀?qū)節(jié)點(diǎn)已設(shè)置為 SIGNAL,所以會直接返回 true,執(zhí)行線程阻塞操作

LockSupport.park 方法將當(dāng)前等待隊(duì)列中線程進(jìn)行阻塞操作,線程執(zhí)行一個從 RUNNABLE 到 WAITING 狀態(tài)轉(zhuǎn)變

如果線程被喚醒,通過執(zhí)行 Thread.interrupted 查看中斷狀態(tài),這里的中斷狀態(tài)會被傳遞到 acquire 方法

即使線程從 park 方法中喚醒后發(fā)現(xiàn)自己被中斷了,但是不影響接下來的獲取鎖操作,如果需要設(shè)置線程中斷來影響流程,可以使用 lockInterruptibly 獲得鎖,拋出檢查異常 InterruptedExceptio

cancelAcquire

取消排隊(duì)方法是 AQS 中比較難的知識點(diǎn),不容易被理解

當(dāng)線程因?yàn)樽孕蛘弋惓5惹闆r獲取鎖失敗,會調(diào)用此方法進(jìn)行取消正在獲取鎖的操作

邏輯稍微復(fù)雜一些,比較重要是以下三個邏輯

  1. 步驟一當(dāng)前節(jié)點(diǎn)為尾節(jié)點(diǎn)的話,設(shè)置 pred 節(jié)點(diǎn)為新的尾節(jié)點(diǎn),成功設(shè)置后再將 pred 后繼節(jié)點(diǎn)設(shè)置為空(尾節(jié)點(diǎn)不會有后繼節(jié)點(diǎn))
  2. 步驟二需要滿足以下四個條件才會將前驅(qū)節(jié)點(diǎn)(非取消狀態(tài))的后繼指針指向當(dāng)前節(jié)點(diǎn)的后繼指針1)當(dāng)前節(jié)點(diǎn)不等于尾節(jié)點(diǎn)2)當(dāng)前節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)不等于頭節(jié)點(diǎn)3)前驅(qū)節(jié)點(diǎn)的等待狀態(tài)不為取消狀態(tài)4)前驅(qū)節(jié)點(diǎn)的擁有線程不為空
  3. 如果不滿足步驟二的話,會執(zhí)行步驟三相關(guān)邏輯,喚醒后繼節(jié)點(diǎn)

步驟一:

假設(shè)當(dāng)前取消節(jié)點(diǎn)為尾節(jié)點(diǎn)并且前置節(jié)點(diǎn)無取消節(jié)點(diǎn),現(xiàn)有等待隊(duì)列如下圖,執(zhí)行下述邏輯

將 pred 設(shè)置為新的尾節(jié)點(diǎn),并將 pred 后繼節(jié)點(diǎn)設(shè)置為空,因?yàn)槲补?jié)點(diǎn)不會有后繼節(jié)點(diǎn)了

T4 線程所在節(jié)點(diǎn)因無引用指向,會被 GC 垃圾回收處理

步驟二:

如果當(dāng)前需要取消節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)為取消狀態(tài)節(jié)點(diǎn),如圖所示

設(shè)置 pred(非取消狀態(tài))的后繼節(jié)點(diǎn)為 node 的后繼節(jié)點(diǎn),并設(shè)置 node 的 next 為 自己本身

線程T2、T3所在節(jié)點(diǎn)因?yàn)楸籘4所直接或間接指向,如何進(jìn)行GC?

AQS 等待隊(duì)列中取消狀態(tài)節(jié)點(diǎn)會在 shouldParkAfterFailedAcquire 方法中被 GC 垃圾回收

T4 線程所在節(jié)點(diǎn)獲取鎖失敗嘗試停止時,會執(zhí)行上述代碼,執(zhí)行后的等待隊(duì)列如下圖所示

等待隊(duì)列中取消狀態(tài)節(jié)點(diǎn)就可以被 GC 垃圾回收了,至此加鎖流程也就結(jié)束了,下面繼續(xù)看如何解鎖

獨(dú)占解鎖源碼解析

解鎖流程相對于加鎖簡單了很多,調(diào)用對應(yīng)API-lock.unlock()

釋放鎖同步狀態(tài)

tryRelease 是定義在 AQS 中的抽象方法,通過 Sync 類重寫了其實(shí)現(xiàn)

喚醒后繼節(jié)點(diǎn)

此時 State 值已被釋放,對于頭節(jié)點(diǎn)的判斷這塊流程比較有意思

什么情況下頭節(jié)點(diǎn)為空,當(dāng)線程還在爭奪鎖,隊(duì)列還未初始化,頭節(jié)點(diǎn)必然是為空的

當(dāng)頭節(jié)點(diǎn)等待狀態(tài)等于0,證明后繼節(jié)點(diǎn)還在自旋,不需要進(jìn)行后繼節(jié)點(diǎn)喚醒

如果同時滿足上述兩個條件,會對等待隊(duì)列頭節(jié)點(diǎn)的后繼節(jié)點(diǎn)進(jìn)行喚醒操作

為什么查找隊(duì)列中未被取消的節(jié)點(diǎn)需要從尾部開始?

這個問題有兩個原因可以解釋,分別是 Node 入隊(duì)和清理取消狀態(tài)的節(jié)點(diǎn)

  1. 先從 addWaiter 入隊(duì)時說起,compareAndSetTail(pred, node)、pred.next = node 并非原子操作,如果在執(zhí)行 pred.next = node 前進(jìn)行 unparkSuccessor,就沒有辦法通過 next 指針向后遍歷,所以才會從后向前找尋非取消的節(jié)點(diǎn)
  2. cancelAcquire 方法也有導(dǎo)致使用 head 無法遍歷全部 Node 的因素,因?yàn)橄葦嚅_的是 next 指針,prev 指針并未斷開
喚醒阻塞后流程

當(dāng)線程獲取鎖失敗被 park 后進(jìn)入了阻塞模式,前驅(qū)節(jié)點(diǎn)釋放鎖后會進(jìn)行喚醒 unpark,被阻塞線程狀態(tài)回歸 RUNNABLE 狀態(tài)

被喚醒線程檢查自身是否被中斷,返回自身中斷狀態(tài)到 acquireQueued

假設(shè)自身被中斷,設(shè)置 interrupted = true,繼續(xù)通過循環(huán)嘗試獲取鎖,獲取鎖成功后返回 interrupted 中斷狀態(tài)

中斷狀態(tài)本身并不會對加鎖流程產(chǎn)生影響,被喚醒后還是會不斷進(jìn)行獲取鎖,直到獲取鎖成功進(jìn)行返回,返回中斷狀態(tài)是為了后續(xù)補(bǔ)充中斷紀(jì)錄

如果線程被喚醒后發(fā)現(xiàn)中斷,成功獲取鎖后會將中斷狀態(tài)返回,補(bǔ)充中斷狀態(tài)

selfInterrupt 就是對線程中斷狀態(tài)的一個補(bǔ)充,補(bǔ)充狀態(tài)成功后,流程結(jié)束

閱讀源碼小技巧

1、從全局掌握要閱讀的源碼提供了什么功能

這也是我一直推崇的學(xué)習(xí)源碼方式,學(xué)習(xí)源碼的關(guān)鍵點(diǎn)是抓住主線流程,在了解主線之前不要最開始就研究到源碼實(shí)現(xiàn)細(xì)節(jié)中,否則很容易迷失在細(xì)枝末節(jié)的代碼中

以文章中的 AQS 舉例,當(dāng)你知道了它是一個抽象隊(duì)列同步器,使用它可以更簡單的構(gòu)造鎖和同步器等實(shí)現(xiàn)

然后從中理解 tryAcquire、tryRelease 等方法實(shí)現(xiàn),這樣是不是可以更好的理解與 AQS 與其子類相關(guān)的代碼

2、把不易理解的源碼粘貼出來,整理好格式打好備注

一般源碼中的行為格式和我們?nèi)粘G么a是不一樣的,而且 JDK 源碼中的變量命名實(shí)在是慘不忍睹

所以就應(yīng)該將難以理解的源碼粘貼出,標(biāo)上對應(yīng)注釋以及調(diào)整成易理解的格式,這樣對于源碼的閱讀就會輕松很多

后記

平常工作中接觸到 AQS 相關(guān)知識還是很多的,知其然知其所以然,文章以 ReentrantLock 作為切入點(diǎn),講述了其公平鎖和非公平鎖的概念,以及對應(yīng) AQS 中 CLH、AOS 等不容易被發(fā)現(xiàn)的概念

針對 ReentrantLock 以及 AQS 加鎖、解鎖、排隊(duì)等流程進(jìn)行了詳細(xì)說明,以圖文并茂的方式講述了其流程源碼實(shí)現(xiàn)細(xì)節(jié),這里希望在看的小伙伴都能收獲 AQS 相關(guān)知識

作者:馬稱

原文鏈接:https://machen.blog.csdn.net/article/details/109758867

熱點(diǎn)圖片

備案號:贛ICP備2022005379號
華網(wǎng)(http://www.acmerblog.com) 版權(quán)所有未經(jīng)同意不得復(fù)制或鏡像

QQ:51985809郵箱:51985809@qq.com

国产一区在线不卡_国产精品天天摸av网_日韩精品中文字幕第1页_国产精品无码专区在线观看
在线视频精品一区| 亚洲电影下载| 亚洲精品综合| 国产亚洲精品资源在线26u| 欧美黑人国产人伦爽爽爽| 一区二区三区高清不卡| 亚洲国产毛片完整版 | a4yy欧美一区二区三区| 在线观看欧美一区| 韩日精品中文字幕| 国产日韩高清一区二区三区在线| 欧美激情亚洲视频| 欧美成人官网二区| 欧美夫妇交换俱乐部在线观看| 久久精品99国产精品| 亚洲欧美在线磁力| 亚洲女人天堂av| 亚洲男人第一av网站| 亚洲欧美日韩精品| 亚洲一区三区电影在线观看| 国产精品99久久99久久久二8| 亚洲精品一区中文| 一本色道久久综合亚洲91| 最新亚洲视频| 亚洲娇小video精品| 亚洲激情综合| 亚洲免费激情| 亚洲一级黄色| 欧美一区二区免费观在线| 欧美一区日本一区韩国一区| 欧美在线视频播放| 久久久久久久久久久久久久一区| 久久久亚洲高清| 久久久久高清| 免费观看一级特黄欧美大片| 欧美成人精品影院| 欧美日韩免费高清一区色橹橹| 欧美无砖砖区免费| 国产欧美精品在线| 激情欧美一区二区三区| 欧美视频一区二区三区| 嫩草影视亚洲| 欧美大片在线观看一区| 欧美亚州韩日在线看免费版国语版| 欧美三级网址| 国产亚洲一级高清| 亚洲精选国产| 香港久久久电影| 久久久久久九九九九| 欧美精品福利| 国产真实乱子伦精品视频| 亚洲激情小视频| 亚洲综合激情| 国产欧美一区二区三区另类精品| 国产伦精品一区二区三区免费迷| 韩国在线视频一区| 亚洲美女视频| 亚洲影视中文字幕| 欧美成人日本| 国产精品久久久久高潮| 欧美性猛交99久久久久99按摩| 欧美久久久久久久久| 国产在线欧美日韩| 亚洲三级国产| 久久综合网络一区二区| 欧美诱惑福利视频| 欧美四级电影网站| 亚洲二区视频在线| 亚洲欧美精品在线| 欧美国产在线观看| 欧美精品激情在线观看| 国产在线精品二区| 亚洲免费在线观看| 欧美国产国产综合| 国内精品**久久毛片app| 亚洲视频在线播放| 久久久青草青青国产亚洲免观| 欧美日韩一区二区三区在线看| 欧美午夜久久久| 亚洲美女黄网| 久久精品中文字幕一区| 国产日韩综合一区二区性色av| 亚洲一区二区三区777| 欧美日韩色一区| 99精品国产在热久久下载| 久久福利精品| 国产一区亚洲| av72成人在线| 欧美激情一区二区三区成人| 国产一区视频在线观看免费| 亚洲免费精品| 欧美日本国产精品| 国产日韩欧美高清免费| 一区二区三区日韩精品视频| 欧美日韩亚洲一区二区三区在线| 欧美日韩一区二区三区四区五区| 日韩视频免费看| 欧美二区在线看| 亚洲人成人一区二区三区| 久久九九99| 国产精品嫩草久久久久| 这里只有精品丝袜| 国产精品多人| 宅男66日本亚洲欧美视频| 蜜臀99久久精品久久久久久软件| 国产精品自拍在线| 午夜一区二区三区在线观看| 欧美成在线观看| 亚洲第一搞黄网站| 欧美亚洲视频| 国产精品午夜在线观看| 亚洲激情另类| 欧美在线播放高清精品| 欧美揉bbbbb揉bbbbb| 影音先锋在线一区| 久久激情网站| 99在线热播精品免费99热| 国产精品网站在线播放| 亚洲国产老妈| 久久露脸国产精品| 国产精品激情电影| 亚洲国产91精品在线观看| 欧美在线观看日本一区| 永久久久久久| 欧美在线日韩| 亚洲手机在线| 国产精品99一区二区| aaa亚洲精品一二三区| 国产精品日韩欧美大师| 你懂的视频欧美| 欧美在线视频在线播放完整版免费观看 | 亚洲精品小视频| 国产精品久久国产精麻豆99网站| 亚洲综合欧美日韩| 91久久精品www人人做人人爽| 国产区日韩欧美| 国产精品福利网| 欧美成人精精品一区二区频| 欧美在线视频观看免费网站| 在线视频欧美日韩| 亚洲日本成人女熟在线观看| 国内精品久久久久久影视8 | 99天天综合性| 国产真实久久| 国产视频一区在线观看| 欧美性猛交99久久久久99按摩| 蜜臀va亚洲va欧美va天堂| 久久福利影视| 亚洲欧美综合v| 亚洲欧美日韩一区在线观看| 日韩一级黄色大片| 亚洲免费电影在线| 亚洲精品视频二区| 亚洲精选国产| 一本色道久久综合狠狠躁篇的优点 | 久久成人精品一区二区三区| 99热这里只有成人精品国产| 亚洲成人在线免费| 韩日成人在线| 亚洲成色777777女色窝| 一区精品在线| 在线日韩精品视频| 亚洲国产综合在线看不卡| 在线精品视频一区二区三四| 激情综合五月天| 亚洲成在线观看| 亚洲伦理在线观看| 99成人精品| 亚洲影音先锋| 欧美在线观看视频一区二区三区| 欧美亚洲综合另类| 麻豆精品在线播放| 欧美母乳在线| 国产精品成人免费精品自在线观看| 欧美视频中文字幕在线| 在线观看三级视频欧美| 亚洲国产婷婷香蕉久久久久久| 亚洲高清不卡一区| 一区二区三区导航| 久久av红桃一区二区小说| 麻豆9191精品国产| 欧美日韩免费观看一区二区三区| 每日更新成人在线视频| 欧美激情第五页| 国产精品欧美久久久久无广告| 国产精品福利久久久| 午夜精彩视频在线观看不卡| 一区二区三区四区五区精品视频| 欧美一级黄色录像| 久久综合九九| 欧美视频二区| 一区免费视频| 亚洲一级电影| 欧美国产一区二区| 国产精品有限公司| 亚洲精品欧美专区| 久久久伊人欧美| 国产精品国产a级| 亚洲激情在线视频| 久久岛国电影|