ReentrantLock源碼解析

ReentrantLock源碼解析

文章目錄

  • ReentrantLock源碼解析
    • 一、ReentrantLock
    • 二、ReentrantLock 的 Sync、FairSync、NonfairSync
      • 2.1 Sync、FairSync、NonfairSync
      • 2.2 NonfairSync 下的 tryAcquire
      • 2.3 FairSync下的 tryAcquire
      • 2.4 tryRelease
    • 三、lock.lock()
      • 3.1 NonfairSync.lock()
      • 3.2 FairSync.lock()
    • 四、lock.unlock()
    • 五、總結

一、ReentrantLock

ReentrantLock 是 Java JUC 中的一個可重入鎖ReentrantLock鎖 是基于 AQS 實現的。

AQS 中,如果需要使用AQS的特征則需要子類根據使用的場景,重寫下面方法:

//查詢是否正在獨占資源,condition會使用
boolean isHeldExclusively()	
//獨占模式,嘗試獲取資源,成功則返回true,失敗則返回false
boolean tryAcquire(int arg)
//獨占模式,嘗試釋放資源,成功則返回true,失敗則返回false
boolean tryRelease(int arg)
//共享模式,嘗試獲取資源,如果返回負數表示失敗,否則表示成功。
int tryAcquireShared(int arg)
//共享模式,嘗試釋放資源,成功則返回true,失敗則返回false。
boolean tryReleaseShared(int arg)

由于這里 ReentrantLock 鎖的特性,所以下面只需關注獨占模式下的幾個方法即可。

關于 AQS 中的方法解析可跳轉查看 AQS源碼解析 這篇文章

下面開始 ReentrantLock 源碼的分析:

二、ReentrantLock 的 Sync、FairSync、NonfairSync

2.1 Sync、FairSync、NonfairSync

在聲明 ReentrantLock 鎖時,有兩種方式,一種是無參構造函數,一種則需要指定一個 fair 參數:

  • new ReentrantLock();
  • new ReentrantLock(false);

當使用無參構造函數聲明時,則是創建了一個 NonfairSync 對象:
在這里插入圖片描述

通過有參的構造函數,則根據傳入的 fair 可以選擇創建一個 FairSync 對象:
在這里插入圖片描述

其實這里也不難理解 NonfairSyncFairSync 其實就是ReentrantLock 鎖中的非公平鎖和公平鎖兩種類型。

點到這兩個類中,可以看到都繼承自 Sync 類:
在這里插入圖片描述

Sync 類,則繼承了 AQS
在這里插入圖片描述

到這里,我們尋找幾個關鍵的方法,在AQS中獨占模式下,兩大關鍵的方法是交由子類進行實現的,分別是 tryAcquire() 嘗試獲取資源,和 tryRelease() 嘗試釋放資源。

首先來看 tryAcquire() 嘗試獲取資源:

通過 Sync 類的實現源碼發現并沒有重寫 tryAcquire() 方法,那該方法肯定在下面的子類FairSyncNonfairSync ,分別看下源碼確實存在重寫的方法:

在這里插入圖片描述
在這里插入圖片描述

2.2 NonfairSync 下的 tryAcquire

首先看下 NonfairSynctryAcquire() 實現邏輯,可以看到又調用了 nonfairTryAcquire() 就是 Sync 類中的 nonfairTryAcquire() ,從命名上可以分析出就是非公平鎖的嘗試獲取資源,直觀就是非公平鎖下獲取鎖操作:
在這里插入圖片描述

進入到 Sync 類中的 nonfairTryAcquire()中,可以看到首先獲取到 AQS 中的共享資源 state,如果 state 等于 0 ,則將 state 的值修改為 acquires(默認為1,下面會分析到),并設置AQS的獨占線程為當前線程,并返回 true ,說白了不就是獲取到鎖了嗎,那就可以理解為 state 等于 0 即是無鎖的狀態,下面將 state 的值修改為 acquires 就是獲取到鎖了,改變資源的狀態:
在這里插入圖片描述

接著如果 state 的值不是 0 ,則當前鎖已經被別的線程持有了,這里又判斷了下,如果持有鎖的線程正好是當前的線程,那不就是鎖的重入嗎,這種情況下可以直接獲得鎖,不過這里為了記錄重入的次數,對 state 共享資源進行了 + acquires 操作,其實就是 +1 操作。

在這里插入圖片描述

如果都沒有成功,那此時則獲取鎖失敗,返回 false

2.3 FairSync下的 tryAcquire

FairSync 類下的 tryAcquire() 方法中,和前面 NonfairSync 類似,但不同的是,在獲取到鎖時,也就是拿到 state 等于 0,進行修改資源時,多了步 hasQueuedPredecessors() 的判斷:
在這里插入圖片描述

下面可以進到 hasQueuedPredecessors() 的方法中,可以看到是由 AQS 提供的方法,主要就是判斷當前節點線程的前面是否還有等待的線程,因為 FairSync 實現的是公平鎖的原則,如果當前線程前面還有等待線程,則獲取鎖資源也輪不到自個,讓前面的老大先來:
在這里插入圖片描述

hasQueuedPredecessors() 方法理解后,其余的邏輯則和 NonfairSync() 中的一致了。

2.4 tryRelease

到這里已經了解到了tryAcquire() 嘗試獲取資源的邏輯,上面提到了兩個重要方法,還有一個 tryRelease() 沒有分析邏輯,還是首先看 Sync 類中是否有重寫該方法:

通過源碼可以看到,在 Sync 類中就已經對 tryRelease() 進行了重寫,而 NonfairSyncFairSync 中都沒有重寫該方法,那釋放資源就是走的 Sync 類下的 tryRelease() 方法:
在這里插入圖片描述

在該方法中,可以看到首先還是獲取到了 AQS 中的 state 共享資源,然后對該資源進行 - releases (默認releases1,下面會提到)操作,其實就是 -1 操作:
在這里插入圖片描述

接著判斷了下,如果當前線程不是持有鎖線程,就拋出異常,也好理解,沒有持有鎖的線程跑過來釋放鎖,那肯定有問題了呀。

接著再進行判斷 state 是不是等于 0 ,上面講到在鎖重入的情況下,記錄重入的次數是對 state 進行 +1 操作,而這邊又對 state 進行 -1 操作,如果減到最后 state 有成了最初的 0 ,那不就是重入的鎖和當前持有的鎖都釋放完了嗎,這個時候就可以將持有鎖的線程置為空了,并修改最新的 state

在這里插入圖片描述

看到這里就會發現獲取鎖和釋放鎖,無非就是對 AQS 中的共享資源進行操作。理解了這兩大核心的方法后,下面就可以看如何運用在 ReentrantLock 中的了。

三、lock.lock()

ReentrantLock 中,需要獲取鎖時,直接使用 lock.lock() 即可,那 lock.lock() 到底做了什么呢,點到該方法中,可以看到是調用的 Synclock() 方法,而 Sync 中的 lock() 方法是抽象方法,具體實現肯定在子類的 NonfairSyncFairSync 中。

在這里插入圖片描述

3.1 NonfairSync.lock()

首先點進 NonfairSync 非公平鎖中的 lock() 方法,直接進行了將 AQS 中的共享資源 state0 改為 1 ,如果修改成功,根據上面分析的結論不就是獲取鎖成功了嗎,可以將 AQS中的獨占線程設為自己了。但是如果其他線程修改成功了,這里使用 CAS 就會修改失敗,因此就會進到 acquire() 方法,注意這里傳遞的參數默認就是 1 ,對應著前面括號中的說明:
在這里插入圖片描述

acquire() 方法,就是 AQS 中的獨占模式獲取同步資源的邏輯,會調用當前方法的 tryAcquire() 嘗試獲取資源,如果獲取不到,則加入到 AQS 的阻塞隊列并阻塞掛起線程。
在這里插入圖片描述

關于 acquire 方法的源碼解析可查看 AQS源碼解析 。

3.2 FairSync.lock()

FairSync 公平鎖中,由于需要遵循先進先出的原則,這里沒有直接已粗暴的形式對 state 進行修改,而是直接調用了 AQS 中的 acquire() 方法,而 acquire() 方法又會調用當前類的 tryAcquire() 獲取資源。

但在當前類的 tryAcquire() 方法中,如果獲取到了資源,會接著進行判斷當前線程的前面是否還有等待的線程,如果有則讓出來讓別人獲取資源,因此就遵循了公平鎖的原則,注意這里傳遞的參數默認就是 1 ,同樣對應著前面括號中的說明:
在這里插入圖片描述

同樣 tryAcquire() 嘗試獲取資源,如果獲取不到,則加入到 AQS 的阻塞隊列并阻塞掛起線程。

四、lock.unlock()

上面了解到了 lock() 的邏輯,既然上鎖了肯定需要解鎖,下面點到 unlock() 方法中,可以看到直接使用了 Syncrelease() 方法釋放資源,其實是 AQS 中的 release() 方法,注意這里傳遞的參數默認就是 1,同樣對應著前面括號中的說明:
在這里插入圖片描述

AQSrelease() 方法中,首先會調用 Sync 類的 tryRelease() 釋放資源,然后對已阻塞的線程進行喚醒:
在這里插入圖片描述

關于 release() 方法的源碼解析可查看 AQS源碼解析 。

五、總結

通過閱讀 ReentrantLock 的源碼可以發現,大量依賴于 AQS 中提供的方法,所以在閱讀前一定要理解下 AQS 的作用和功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165063.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165063.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165063.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

優橙內推青海專場——5G網絡優化(中高級)工程師

可加入就業QQ群:801549240 聯系老師內推簡歷投遞郵箱:hrictyc.com 內推公司1:浙江明訊網絡技術有限公司 內推公司2:南京華蘇科技有限公司 內推公司3:杭州華星創業通信技術有限公司 浙江明訊網絡技術有限公司 浙江明…

4.常見面試題--操作系統

特點:并發性、共享性、虛擬性、異步性。 Windows 和 Linux 內核差異 對于內核的架構?般有這三種類型: ● 宏內核,包含多個模塊,整個內核像?個完整的程序; ● 微內核,有?個最?版本的內核&#xff0…

名字大卻不中用的AI大模型,名不副實

這兩天 OpenAI 團隊( ChatGPT 公司)的戲比較多,兩三天的功夫,劇情發展都超出了 OpenAI 首席科學家的預期,目前來看,微軟還是最大的贏家。這是個引子,這個話題,網絡上早已傳爛了&…

云安全之盾:ZStack 云主機安全防護解決方案全方位保護云環境

隨著云計算的蓬勃發展,網絡威脅愈發復雜,涵蓋了從勒索病毒到APT攻擊的各種威脅類型。在這一風云變幻的網絡安全環境下,云主機安全不再僅僅是一個選項,它是信息系統安全的核心要素。云軸科技ZStack 云主機安全防護解決方案是為了滿…

6.3.WebRTC中的SDP類的結構

在上節課中呢,我向你介紹了sdp協議, 那這節課呢,我們再來看看web rtc中。是如何存儲sdp的?也就是sdp的類結構,那在此之前呢?我們先對sdp的內容啊,做一下分類。因為在上節課中呢,雖然…

Python+jieba+wordcloud實現文本分詞、詞頻統計、條形圖繪制及不同主題的詞云圖繪制

目錄 序言:第三方庫及所需材料函數模塊介紹分詞詞頻統計條形圖繪制詞云繪制主函數 效果預覽全部代碼 序言:第三方庫及所需材料 編程語言:Python3.9。 編程環境:Anaconda3,Spyder5。 使用到的主要第三方庫:…

python之pyqt專欄1-環境搭建

#python pyqt# python:3.11.6 pycharm:PyCharm Community Edition 2023.2.5 pyqt6 python安裝 官網下載:Python Releases for Windows | Python.org pycharm社區版安裝 官網地址:Download PyCharm: Python IDE for Professional…

golang學習筆記——創建項目

創建項目 從Go 1.8開始,將GOPATH設置為環境變量不是必需的。如果我們沒有設置一個,Go使用默認的GOPATH為$HOME/go。可以使用go env查看環境變量信息。 創建項目 # 創建項目目錄 mkdir helloLog cd helloLog # 使用go mod初始化項目,生成go.mod文件 go…

TikTok shop印尼重啟電商征程:與當地平臺合作開啟新篇章!——站斧瀏覽器

經歷了一個半月的間隔,TikTok Shop成功重返印度尼西亞市場。據國際媒體報道,TikTok計劃通過與印尼本地電子商務平臺的合作,重啟其在該國的電商業務。 Temmy Satya Permana,印尼合作社和中小企業部的官員,證實了這一重…

【廣州華銳互動】VR線上課件制作軟件滿足數字化教學需求

隨著科技的不斷發展,虛擬現實(VR)技術在教學領域的應用逐漸成為趨勢。其中,廣州華銳互動開發的VR線上課件制作軟件更是備受關注。這種工具為教師提供了便捷的制作VR課件的手段,使得VR教學成為可能,極大地豐…

thinkphp6 不支持:redis錯誤

起因: 使用 redis 時候,thinkphp 報錯。 解決方法: 打開 php.ini 文件,增加 extensionphp_redis.dll 即可

Java架構師發展方向和歷程

目錄 1 導論2 架構師的三觀培養3 架構師的遇到的困難4 架構師職責5 架構師之路6 架構師的發展方向7 應用領域架構師8 業務架構師9 系統架構師和企業架構師10 技術路線和演進規劃11 一線大廠的技術生態拓張案例12 如何推進項目落地想學習架構師構建流程請跳轉:Java架構師系統架…

CUDA與GPU編程

文章目錄 CUDA與GPU編程1. 并行處理與GPU體系架構1.1 并行處理簡介1.1.1 串行處理與并行處理的區別1.1.2 并行處理的概念1.1.3 常見的并行處理 1.2 GPU并行處理1.2.1 GPU與CPU并行處理的異同1.2.2 CPU的優化方式1.2.3 GPU的特點 1.3 環境搭建 CUDA與GPU編程 1. 并行處理與GPU體…

城市管理實景三維:打造智慧城市的新引擎

城市管理實景三維:打造智慧城市的新引擎 在城市管理領域,實景三維技術正逐漸成為推動城市發展的新引擎。通過以精準的數字模型呈現城市真實場景,實景三維技術為城市決策提供了全新的思路和工具。從規劃設計到交通管理,從環境保護到…

嵌入式系統在工業自動化中的應用

嵌入式系統在工業自動化中的應用非常廣泛,它們通過集成控制和實時響應能力,實現了生產線的自動化、智能化和高效化。以下將詳細介紹嵌入式系統在工業自動化中的幾個重要應用領域,并提供一些示例代碼。 1. PLC(可編程邏輯控制器&a…

【開源】基于Vue和SpringBoot的學校熱點新聞推送系統

項目編號: S 047 ,文末獲取源碼。 \color{red}{項目編號:S047,文末獲取源碼。} 項目編號:S047,文末獲取源碼。 目錄 一、摘要1.1 項目介紹1.2 項目錄屏 二、功能模塊2.1 新聞類型模塊2.2 新聞檔案模塊2.3 新…

Python模塊之yaml:簡化配置與數據解析

更多Python學習內容:ipengtao.com YAML(YAML Aint Markup Language)是一種人類可讀的數據序列化格式,常用于配置文件和數據傳輸。在Python中,可以使用PyYAML模塊來處理YAML格式的數據。本文將深入介紹PyYAML的基礎用法…

力扣H指數——簡約做法

Problem: 274. H 指數 文章目錄 思路解題方法復雜度Code 思路 最后的結果一定不會超過下標個數。應為文章也要大于這個h,h超過了文章總數,就永遠不會存在這么多的文章滿足條件,所以只需要循環下標,那么最后的結果呢? 解…

AI質差小區優化效果評估

1. 下行流量/PRB利用率和貶損用戶的關系 通過分析長期貶損質差小區:下行PRB利用率/流量和小區平均每小時質差用戶數成正比例關系,即小區的貶損用戶會隨PRB利用率/流量的增長而增長。 2. 貶損用戶和流量走勢 年前平均每天流量平穩的情況下,通…

關于JS stack trace解決辦法

問題描述 npm run serve啟動前端項目時&#xff0c;控制臺輸出下圖一堆的文字&#xff0c;JS stack trace , 問題現象&#xff1a; JS stack trace Security context: 0000017B93ACFB61 <JS Object>1: init_scope_vars [0000017B93A04381 <undefined>:~3382] [p…