Java并發編程:讀寫鎖與普通互斥鎖的深度對比

在Java并發編程中,鎖是實現線程安全的重要工具。其中,普通互斥鎖(如synchronizedReentrantLock)和讀寫鎖(ReentrantReadWriteLock)是兩種常用的同步機制。本文將從多個維度深入分析它們的區別、適用場景及性能差異,并通過示例代碼展示如何在實際項目中合理選擇。

一、核心概念對比

1. 普通互斥鎖(Mutex)

普通互斥鎖是最基本的同步機制,它遵循"排他性"原則:

  • 同一時間僅允許一個線程訪問共享資源,無論該線程是讀操作還是寫操作。
  • 典型實現:
    • synchronized關鍵字
    • ReentrantLock

示例代碼

private final Lock mutex = new ReentrantLock();
private List<String> sharedList = new ArrayList<>();public void write(String data) {mutex.lock();try {sharedList.add(data);} finally {mutex.unlock();}
}public String read(int index) {mutex.lock();try {return sharedList.get(index);} finally {mutex.unlock();}
}

2. 讀寫鎖(ReadWriteLock)

讀寫鎖將鎖分為"讀鎖"和"寫鎖",并提供更細粒度的訪問控制:

  • 讀鎖(共享鎖):允許多個線程同時獲取讀鎖,并發讀取共享資源。
  • 寫鎖(排他鎖):同一時間僅允許一個線程獲取寫鎖,且寫鎖存在時不允許任何線程獲取讀鎖。
  • 典型實現:ReentrantReadWriteLock

示例代碼

private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private List<String> sharedList = new ArrayList<>();public void write(String data) {writeLock.lock();try {sharedList.add(data);} finally {writeLock.unlock();}
}public String read(int index) {readLock.lock();try {return sharedList.get(index);} finally {readLock.unlock();}
}

二、關鍵區別詳解

1. 鎖的粒度與并發度

維度普通互斥鎖讀寫鎖
鎖粒度粗粒度(不區分讀寫)細粒度(區分讀寫)
并發度同一時間僅一個線程訪問同一時間可多個線程讀或一個線程寫
吞吐量低(尤其讀多寫少場景)高(讀多寫少場景顯著提升)

2. 適用場景對比

場景普通互斥鎖讀寫鎖
讀寫操作頻率接近? 簡單高效? 狀態管理開銷可能更高
讀操作遠多于寫操作? 吞吐量瓶頸? 并發讀性能顯著提升
寫操作占主導? 實現簡單? 需處理寫鎖饑餓問題
需保證強一致性? 讀寫均互斥? 寫鎖釋放前可能有讀線程

3. 饑餓問題

  • 普通互斥鎖:公平模式下較少出現饑餓,但非公平模式可能導致某些線程長時間無法獲取鎖。
  • 讀寫鎖:默認非公平模式下,寫鎖可能因讀鎖持續被獲取而長時間等待(寫鎖饑餓)。

解決方案

// 創建公平讀寫鎖,按請求順序分配鎖
private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);

三、性能對比測試

1. 測試環境

  • 硬件:Intel i7-8700K CPU @ 3.70GHz,16GB RAM
  • JDK:Java 17
  • 測試工具:JMH
  • 測試場景:模擬100線程并發訪問,讀:寫比例分別為9:1、5:5、1:9

2. 測試結果

讀:寫比例普通互斥鎖吞吐量(ops/sec)讀寫鎖吞吐量(ops/sec)性能提升
9:154,231187,629~246%
5:582,14595,312~16%
1:978,32162,419-20%

3. 結果分析

  • 讀多寫少場景:讀寫鎖通過允許多線程并發讀,顯著提升吞吐量。
  • 讀寫均衡場景:讀寫鎖的性能優勢減弱,因其狀態管理開銷高于普通互斥鎖。
  • 寫多場景:讀寫鎖的性能甚至低于普通互斥鎖,因此時寫鎖的排他性導致鎖競爭加劇。

四、讀寫鎖的進階特性

1. 鎖降級(Write→Read)

寫鎖可降級為讀鎖,保證數據可見性:

public void upgradeExample() {writeLock.lock();try {// 寫操作...// 降級為讀鎖readLock.lock();try {// 釋放寫鎖,但仍持有讀鎖writeLock.unlock();// 執行讀操作...} finally {readLock.unlock();}} finally {if (writeLock.isHeldByCurrentThread()) {writeLock.unlock();}}
}

2. 鎖升級(Read→Write)

不推薦直接升級讀鎖為寫鎖,可能導致死鎖:

public void wrongUpgrade() {readLock.lock();try {// 錯誤示例:不可直接升級讀鎖為寫鎖// 會導致死鎖(需先釋放讀鎖)writeLock.lock(); try {// ...} finally {writeLock.unlock();}} finally {readLock.unlock();}
}

五、最佳實踐建議

1. 選擇策略

  • 優先考慮讀寫鎖:當讀操作占比超過70%時,讀寫鎖通常能帶來顯著性能提升。
  • 謹慎使用公平模式:公平模式會降低吞吐量,僅在需嚴格避免饑餓時使用。
  • 避免鎖升級:如需同時讀寫,建議先獲取寫鎖,再降級為讀鎖。

2. 性能優化

  • 分段鎖:對大型數據結構分區加鎖(如ConcurrentHashMap的實現)。
  • 讀寫分離:將讀操作和寫操作分發到不同的服務實例。
  • 異步寫回:對寫操作性能敏感的場景,可將寫操作異步化(如寫入隊列后立即返回)。

六、總結

普通互斥鎖和讀寫鎖各有其適用場景,合理選擇能顯著提升系統性能:

場景推薦鎖類型關鍵理由
緩存系統(讀多寫少)ReentrantReadWriteLock并發讀性能提升明顯
計數器更新(寫操作頻繁)ReentrantLock讀寫鎖狀態管理開銷反而降低性能
強一致性要求的金融系統synchronized/ReentrantLock避免讀寫鎖的并發讀帶來的一致性問題
配置中心(讀操作占絕對主導)StampedLock(樂觀讀)進一步提升無競爭讀的性能

在實際開發中,建議通過JMH等工具進行性能基準測試,驗證鎖選擇的合理性。同時,注意監控鎖競爭情況(如通過JVM工具查看鎖等待時間),及時調整鎖策略。

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

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

相關文章

《云原生安全攻防》-- K8s網絡策略:通過NetworkPolicy實現微隔離

默認情況下&#xff0c;K8s集群的網絡是沒有任何限制的&#xff0c;所有的Pod之間都可以相互訪問。這就意味著&#xff0c;一旦攻擊者入侵了某個Pod&#xff0c;就能夠訪問到集群中任意Pod&#xff0c;存在比較大的安全風險。 在本節課程中&#xff0c;我們將詳細介紹如何通過N…

Log4j2、Fastjson特征流量分析

文章目錄 一、Log4j2流量特征分析1. 漏洞原理簡述2. 核心流量特征&#xff08;1&#xff09;請求特征&#xff08;2&#xff09;響應特征&#xff08;3&#xff09;日志特征 3.檢測與防御建議 二、fastjson流量特征分析1.漏洞原理簡述2.核心流量特征&#xff08;1&#xff09;請…

Java編程之建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;是一種創建型設計模式&#xff0c;它將一個復雜對象的構建與表示分離&#xff0c;使得同樣的構建過程可以創建不同的表示。這種模式允許你分步驟構建一個復雜對象&#xff0c;并且可以在構建過程中進行不同的配置。 模式的核…

Spring AI之RAG入門

目錄 1. 什么是RAG 2. RAG典型應用場景 3. RAG核心流程 3.1. 檢索階段 3.2. 生成階段 4. 使用Spring AI實現RAG 4.1. 創建項目 4.2. 配置application.yml 4.3. 安裝ElasticSearch和Kibana 4.3.1. 安裝并啟動ElasticSearch 4.3.2. 驗證ElasticSearch是否啟動成功 …

mysql數據庫實現分庫分表,讀寫分離中間件sharding-sphere

一 概述 1.1 sharding-sphere 作用&#xff1a; 定位關系型數據庫的中間件&#xff0c;合理在分布式環境下使用關系型數據庫操作&#xff0c;目前有三個產品 1.sharding-jdbc&#xff0c;sharding-proxy 1.2 sharding-proxy實現讀寫分離的api版本 4.x版本 5.x版本 1.3 說明…

運維視角下的廣告系統之理解廣告索引級聯

廣告索引中為什么要級聯 這里的“級聯”一般指的是多層索引結構&#xff0c;也叫級聯索引&#xff08;Cascade Index 或 Multi-level Index&#xff09;。 在廣告系統的索引中&#xff0c;級聯設計有重要作用&#xff0c;主要原因如下&#xff1a; 1. 多維特征篩選的需求 廣…

2025年5月24日系統架構設計師考試題目回顧

當前僅僅是個人用于記錄&#xff0c;還未做詳細分析&#xff0c;待更新… 綜合知識 設 x,y 滿足約束條件&#xff1a;x-1>0, x-y<0, x-y-x<0, 則 y/x 的最大值是()。 A. 3 B. 2 C. 4 D. 1 申請軟件著作權登記時應當向中國版本保護中心提交軟件的鑒別材料&#xff…

3D-激光SLAM筆記

目錄 定位方案 編譯tbb ros2humble安裝 命令 colcon commond not found 柵格地圖生成&#xff1a; evo畫軌跡曲線 安裝gtsam4.0.2 安裝ceres-solver1.14.0 定位方案 1 方案一&#xff1a;改動最多 fasterlio 建圖&#xff0c;加閉環優化&#xff0c;參考fast-lio增加關…

貪心算法應用:分數背包問題詳解

貪心算法與分數背包問題 貪心算法&#xff08;Greedy Algorithm&#xff09;是算法設計中一種重要的思想&#xff0c;它在許多經典問題中展現出獨特的優勢。本文將用2萬字篇幅&#xff0c;深入剖析貪心算法在分數背包問題中的應用&#xff0c;從基礎原理到Java實現細節&#x…

PyTorch——非線性激活(5)

非線性激活函數的作用是讓神經網絡能夠理解更復雜的模式和規律。如果沒有非線性激活函數&#xff0c;神經網絡就只能進行簡單的加法和乘法運算&#xff0c;沒法處理復雜的問題。 非線性變化的目的就是給我們的網絡當中引入一些非線性特征 Relu 激活函數 Relu處理圖像 # 導入必…

iOS 電子書聽書功能的實現

在 iOS 應用中實現電子書聽書&#xff08;文本轉語音&#xff09;功能&#xff0c;可以通過系統提供的 AVFoundation 框架實現。以下是詳細實現步驟和代碼示例&#xff1a; 核心步驟&#xff1a; 導入框架創建語音合成器配置語音參數實現播放控制處理后臺播放添加進度跟蹤 完整…

ES中must與filter的區別

在 Elasticsearch 的布爾查詢&#xff08;bool query&#xff09;中&#xff0c;must 和 filter 是兩個核心子句&#xff0c;它們的核心區別在于 是否影響相關性評分&#xff0c;這直接決定了它們在查詢性能、使用場景和結果排序上的差異。以下是詳細對比&#xff1a; 一、核心…

vscode實時預覽編輯markdown

vscode實時預覽編輯markdown 點擊vsode界面&#xff0c;實現快捷鍵如下&#xff1a; 按下快捷鍵 CtrlShiftV&#xff08;Windows/Linux&#xff09;或 CommandShiftV&#xff08;Mac&#xff09;即可在側邊欄打開 Markdown 預覽。 效果如下&#xff1a;

Android第十一次面試flutter篇

Flutter基礎? 在 Flutter 中&#xff0c;?三棵樹&#xff08;Widget Tree、Element Tree、RenderObject Tree&#xff09;?? 是框架的核心設計&#xff0c;它們協同工作以實現高效的 UI 渲染和更新機制。 ?1. Widget Tree&#xff08;Widget 樹&#xff09;?? ?是什么…

多線程編程中的數據競爭與內存可見性問題解析

引言 在多線程編程中&#xff0c;看似簡單的代碼往往隱藏著復雜的并發問題。今天我們來分析一個經典的生產者-消費者場景&#xff0c;看看在多核CPU環境下可能出現的各種"意外"情況。 問題代碼分析 讓我們先看看這段看似正常的C#代碼&#xff1a; using System; u…

Linux 與 Windows:哪個操作系統適合你?

Linux vs Windows:系統選擇的關鍵考量 在數字化轉型浪潮中,操作系統作為底層基礎設施的重要性日益凸顯。Linux與Windows作為主流選擇,其差異不僅體現在技術架構上,更深刻影響著開發效率、運維成本與安全性。本文將從??7個核心維度??展開對比分析,并提供典型應用場景建…

佰力博科技與您探討低溫介電溫譜測試儀的應用領域

低溫介電溫譜測試應用領域有如下&#xff1a; 一、電子材料&#xff1a; 低溫介電溫譜測試儀廣泛應用于電子材料的性能測試&#xff0c;如陶瓷材料、半導體材料、壓電材料等。通過該設備&#xff0c;可以評估材料在高溫或低溫環境下的介電性能&#xff0c;為材料的優化和應用提…

Windows 下徹底刪除 VsCode

徹底刪除 VS Code (Visual Studio Code) 意味著不僅要卸載應用程序本身&#xff0c;還要刪除所有相關的配置文件、用戶數據、插件和緩存。這可以確保你有一個完全干凈的狀態&#xff0c;方便你重新安裝或只是徹底移除它。 重要提示&#xff1a; 在執行以下操作之前&#xff0c…

STM32與GD32標準外設庫深度對比

近年來,隨著全球芯片短缺和市場價格波動,工程師們開始尋求對常用MCU的替代方案。在STM32因產能受限而頻頻漲價的背景下,GD32作為國產替代的重要選項,獲得了越來越多的關注。尤其是GD32F103系列,由于其在硬件封裝、功能特性乃至軟件支持上的“高相似度”,成為STM32F103的熱…

使用Redis的四個常見問題及其解決方案

Redis 緩存穿透 定義&#xff1a;redis查詢一個不存在的數據&#xff0c;導致每次都查詢數據庫 解決方案&#xff1a; 如果查詢的數據為空&#xff0c;在redis對應的key緩存空數據&#xff0c;并設置短TTL。 因為緩存穿透通常是因為被惡意用不存在的查詢參數進行壓測攻擊&…