深入ReentrantReadWriteLock(一)

一、為什么要出現讀寫鎖

synchronized和ReentrantLock都是互斥鎖。
如果說有一個操作是讀多寫少的,還要保證線程安全的話。如果采用上述的兩種互斥鎖,效率方面很定是很低的。
在這種情況下,咱們就可以使用ReentrantReadWriteLock讀寫鎖去實現。
讀讀之間是不互斥的,可以讀和讀操作并發執行。
但是如果涉及到了寫操作,那么還得是互斥的操作。

static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
static ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
readLock.lock();
try {
System.out.println("子線程!");
try {
Thread.sleep(500000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
readLock.unlock();
}
}).start();Thread.sleep(1000);
writeLock.lock();
try {
System.out.println("主線程!");
} finally {
writeLock.unlock();
}
}

二、讀寫鎖的實現原理

ReentrantReadWriteLock還是基于AQS實現的,還是對state進行操作,拿到鎖資源就去干活,如果沒有拿到,依然去AQS隊列中排隊。
讀鎖操作:基于state的高16位進行操作。
寫鎖操作:基于state的低16為進行操作。
ReentrantReadWriteLock依然是可重入鎖。
寫鎖重入:讀寫鎖中的寫鎖的重入方式,基本和ReentrantLock一致,沒有什么區別,依然是state進行+1操作即可,只要確認持有鎖資源的線程,是當前寫鎖線程即可。只不過之前ReentrantLock的重入次數是state的正數取值范圍,但是讀寫鎖中寫鎖范圍就變小了。
讀鎖重入:因為讀鎖是共享鎖。讀鎖在獲取鎖資源操作時,是要對state的高16位進行 + 1操作。因為讀鎖是共享鎖,所以同一時間會有多個讀線程持有讀鎖資源。這樣一來,多個讀操作在持有讀鎖時,無法確認每個線程讀鎖重入的次數。為了去記錄讀鎖重入的次數,每個讀操作的線程,都會有一個ThreadLocal記錄鎖重入的次數。
寫鎖的饑餓問題:讀鎖是共享鎖,當有線程持有讀鎖資源時,再來一個線程想要獲取讀鎖,直接對state修改即可。在讀鎖資源先被占用后,來了一個寫鎖資源,此時,大量的需要獲取讀鎖的線程來請求鎖資源,如果可以繞過寫鎖,直接拿資源,會造成寫鎖長時間無法獲取到寫鎖資源。
讀鎖在拿到鎖資源后,如果再有讀線程需要獲取讀鎖資源,需要去AQS隊列排隊。如果隊列的前面需要寫鎖資源的線程,那么后續讀線程是無法拿到鎖資源的。持有讀鎖的線程,只會讓寫鎖線程之前的讀線程拿到鎖資源。

三、寫鎖分析

3.1 寫鎖加鎖流程概述

3.2 寫鎖加鎖源碼分析

寫鎖加鎖流程

// 寫鎖加鎖的入口
public void lock() {
sync.acquire(1);
}
// 阿巴阿巴!!
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}
// 讀寫鎖的寫鎖實現tryAcquire
protected final boolean tryAcquire(int acquires) {
// 拿到當前線程
Thread current = Thread.currentThread();
// 拿到state的值
int c = getState();
// 得到state低16位的值
int w = exclusiveCount(c);
// 判斷是否有線程持有著鎖資源
if (c != 0) {
// 當前沒有線程持有寫鎖,讀寫互斥,告辭。
// 有線程持有寫鎖,持有寫鎖的線程不是當前線程,不是鎖重入,告辭。
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 當前線程持有寫鎖。 鎖重入。
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 沒有超過鎖重入的次數,正常 + 1
setState(c + acquires);
return true;
}
// 嘗試獲取鎖資源
if (writerShouldBlock() ||
// CAS拿鎖!compareAndSetState(c, c + acquires))
return false;
// 拿鎖成功,設置占有互斥鎖的線程
setExclusiveOwnerThread(current);
// 返回true
return true;
}
// ================================================================
// 這個方法是將state的低16位的值拿到
int w = exclusiveCount(c);
state & ((1 << 16) - 1)
00000000 00000000 00000000 00000001 == 1
00000000 00000001 00000000 00000000 == 1 << 16
00000000 00000000 11111111 11111111 == (1 << 16) - 1
&運算,一個為0,必然為0,都為1,才為1
// ================================================================
// writerShouldBlock方法查看公平鎖和非公平鎖的效果
// 非公平鎖直接返回false執行CAS嘗試獲取鎖資源
// 公平鎖需要查看是否有排隊的,如果有排隊的,我是否是head的next

3.3 寫鎖釋放鎖流程概述&釋放鎖源碼

釋放的流程和ReentrantLock一致,只是在判斷釋放是否干凈時,判斷低16位的值

// 寫鎖釋放鎖的tryRelease方法
protected final boolean tryRelease(int releases) {
// 判斷當前持有寫鎖的線程是否是當前線程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 獲取state - 1
int nextc = getState() - releases;
// 判斷低16位結果是否為0,如果為0,free設置為true
boolean free = exclusiveCount(nextc) == 0;
if (free)
// 將持有鎖的線程設置為null
setExclusiveOwnerThread(null);
// 設置給state
setState(nextc);
// 釋放干凈,返回true。 寫鎖有沖入,這里需要返回false,不去釋放排隊的Node
return free;
}

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

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

相關文章

React16中打印事件對象取不到值的現象及其原因分析

React16中打印事件對象取不到值的現象及其原因分析 一、背景 在最近的開發過程中&#xff0c;遇到了一個看起來匪夷所思的問題?&#xff1a; <Inputplaceholder"請輸入"onChange{(e) > {console.log(e:, e)}}onKeyDown{handleKeyDown} />此時按理來說我…

旅行商問題(枚舉,回溯,動態規劃,貪心,分支界限)

文章目錄 問題描述暴力枚舉回溯法動態規劃法貪心法分支界限法 問題描述 假設有一個貨郎擔要拜訪n個城市&#xff0c;他必須選擇所要走的路程&#xff0c;路程的限制時每個城市只能拜訪一次&#xff0c;而且最后要走到原來出發的城市&#xff0c;要求路徑長度。 旅行商問題將要…

為銷售賦能:利用 Splashtop 增強遠程培訓技術

遠程銷售團隊這一概念在當今快節奏的商業環境中日益普遍。各公司正在計劃在不同地點靈活開展銷售業務&#xff0c;希望利用技術優勢縮小地域差距。但是&#xff0c;這種向遠程銷售的轉型面臨著重大挑戰&#xff0c;尤其在培訓和發展領域。培訓遠程銷售團隊需要采用創新方法&…

常見樹種(貴州省):012茶、花椒、八角、肉桂、杜仲、厚樸、枸杞、忍冬

摘要&#xff1a;本專欄樹種介紹圖片來源于PPBC中國植物圖像庫&#xff08;下附網址&#xff09;&#xff0c;本文整理僅做交流學習使用&#xff0c;同時便于查找&#xff0c;如有侵權請聯系刪除。 圖片網址&#xff1a;PPBC中國植物圖像庫——最大的植物分類圖片庫 一、茶 灌…

鴻蒙 ark ui 輪播圖實現教程

前言&#xff1a; 各位同學有段時間沒有見面 因為一直很忙所以就沒有去更新博客。最近有在學習這個鴻蒙的ark ui開發 因為鴻蒙不是發布了一個鴻蒙next的測試版本 明年會啟動純血鴻蒙應用 所以我就想提前給大家寫一些博客文章 效果圖 具體實現 我們在鴻蒙的ark ui 里面列表使…

土地利用數據技術服務

一、背景介紹 土地是人類賴以生存與發展的重要資源和物質保障&#xff0c;在“人口&#xff0d;資源&#xff0d;環境&#xff0d;發展&#xff08;PRED&#xff09;”復合系統 中&#xff0c;土地資源處于基礎地位。隨著現代社會人口的不斷增長以及工業化、城市化進程的加速&a…

Excel使用VLOOKUP查詢數據

VLOOKUP函數在百度百科中的解釋是&#xff1a; 解釋一下&#xff0c;函數需要4個參數&#xff1a; 參數1&#xff08;lookup_value&#xff09;&#xff1a;需要匹配的值參數2&#xff08;table_array&#xff09;&#xff1a;在哪個區域里進行匹配參數3&#xff08;col_index…

Dubbo3使用Zookeeper作為注冊中心的方案討論!詳解DubboAdmin與PrettyZoo來監控服務的優劣!

文章目錄 一&#xff1a;Dubbo注冊中心的基本使用 二&#xff1a;Zookeeper注冊中心的使用 1&#xff1a;依賴引入 2&#xff1a;實際開發 三&#xff1a;Zookeeper作為注冊中心的使用展示 1&#xff1a;啟動注冊Zookeeper服務 2&#xff1a;引入注冊中心 (一)&#xf…

Java 21增強對Emoji表情符號的處理了

現一個 Java 21 中有意思的東西&#xff01; 在java.Lang.Character類中增加了用于確定字符是否為 Emoji 表情符號的 API&#xff0c;主要包含下面六個新的靜態方法&#xff1a; public static boolean isEmoji(int codePoint) {return CharacterData.of(codePoint).isEmoji(…

操作系統 day13(RR、優先級調度)

RR&#xff08;時間片輪轉&#xff09; 響應時間&#xff1a;系統中有10個進程正在并發執行&#xff0c;如果時間片為1秒&#xff0c;則一個進程被響應可能需要等待9秒。也就是說&#xff0c;如果用戶在自己進程的時間片外通過鍵盤發出調試命令&#xff0c;可能需要等待9秒才能…

中斷方式的數據接收

中斷接收簡介 回顧之前的代碼 之前的代碼是 等待標志位RXNE位為1才有數據 進而讀取數據存放在變量c中 再根據c變量的數據是為0還是為1進而編寫燈亮滅的代碼 if語句 但這樣的代碼明顯不符合裸機多任務的編程模型 因為在while中為進程 進程執行的時間不能大于5ms 但是while&…

Qt/QML編程學習之心得:一個Qt工程的學習筆記(九)

1、.pro文件 加CONFIG += c++11,才可以使用Lamda表達式(一般用于connect的內嵌槽函數) 2、QWidget 這是Qt新增加的一個類,基類,窗口類,QMainWindow和QDialog都繼承與它。 3、Main函數 QApplication a應用程序對象,有且僅有一個 a.exec() 進行消息循環、阻塞 MyWi…

《圖解Java數據結構與算法:微課視頻版》簡介

本書系統、全面地介紹數據結構的基礎理論與算法設計&#xff0c;精選數據結構考研習題和各類典型例題進行講解&#xff0c;案例和課后習題豐富&#xff0c;突出對數據結構算法實踐能力的培養。本書算法均采用Java語言實現&#xff0c;示例代碼可直接上機運行。 本書配套資源豐…

Spring-jdbcTemplate-配置數據庫連接池,配置文件方式beans.xml

1、jdbc.properties jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql:///studb jdbc.userroot jdbc.pwd123456 2、beans.xml <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans&…

Python BDD 框架比較之 pytest-bdd vs behave

pytest-bdd和behave是 Python 的兩個流行的 BDD 測試框架&#xff0c;兩者都可以用來編寫用戶故事和可執行的測試用例&#xff0c; 具體選擇哪一個則需要根據實際的項目狀況來看。 先簡單看一下兩者的功能&#xff1a; pytest-bdd 基于pytest測試框架&#xff0c;可以與pytest…

港口大型設備狀態監測及預測性維護策略

在現代港口運營中&#xff0c;大型設備的正常運行對于保障港口作業的高效性至關重要。為了實現設備的可靠性和持續性&#xff0c;港口管理者需要采取一系列狀態監測和預測性維護策略。 推進自動化和智能化是提高港口大型設備狀態監測和維護管理效率的重要途徑。通過應用先進的…

【計算機網絡筆記】數據鏈路層概述

系列文章目錄 什么是計算機網絡&#xff1f; 什么是網絡協議&#xff1f; 計算機網絡的結構 數據交換之電路交換 數據交換之報文交換和分組交換 分組交換 vs 電路交換 計算機網絡性能&#xff08;1&#xff09;——速率、帶寬、延遲 計算機網絡性能&#xff08;2&#xff09;…

讀像火箭科學家一樣思考筆記07_探月思維

1. 挑戰“不可能”的科學與企業 1.1. 互聯網 1.1.1. 和電網一樣具有革命性&#xff0c;一旦你插上電源&#xff0c;就能讓自己的生活充滿活力 1.1.2. 互聯網的接入可以幫助人們擺脫貧困&#xff0c;拯救生命 1.1.3. 互聯網還可以提供與天氣相關的信息 1.2. 用廉價、可靠的…

Windows如何截取屏幕圖片以及動態圖

在制作PPT或是其他演示文稿或是說明文檔的時候&#xff0c; 常常需要截取網頁或是屏幕的截圖&#xff0c;在Windows中有多種方式可以實現截取屏幕。 Windows 截取屏幕圖片的方式 在Windows 中截取屏幕中某個區塊的方式有&#xff1a; 方式1. 最原始的方式&#xff1a; 點擊 …

C練習題_2

一、單項選擇題(本大題共20小題,每小題2分,共40分。在每小題給出的四個備選項中選出一個正確的答案&#xff0c;并將所選項前的字母填寫在答題紙的相應位置上。&#xff09; 以下敘述中錯誤的是&#xff08;) A.對于double類型數組&#xff0c;不可以直接用數組名對數組進行整…