Java并發編程性能優化實踐指南:鎖分離與無鎖設計

封面

Java并發編程性能優化實踐指南:鎖分離與無鎖設計

并發場景下的性能瓶頸往往集中在鎖競爭與上下文切換上。本文從鎖分離(Lock Striping)與無鎖設計(Lock-Free)兩大思路出發,深入分析關鍵原理與源碼實現,并結合實戰示例,幫助開發者在高并發系統中獲得穩定且可觀的性能提升。


一、技術背景與應用場景

  1. 高并發數據結構:如緩存、計數器、隊列等,多個線程同時訪問時容易產生鎖競爭。
  2. 熱點資源訪問:對同一共享資源進行寫操作或讀寫混合操作,傳統鎖會成為性能瓶頸。
  3. 低延遲要求:微服務和實時系統中,過多的線程阻塞與上下文切換會影響響應時間。

常見場景:

  • 計數器統計:高并發請求下的PV/UV計數。
  • 緩存更新:頻繁寫入或淘汰策略執行。
  • 消息隊列:生產者/消費者并發入隊出隊。

二、核心原理深入分析

2.1 鎖分離(Lock Striping)

將一個大鎖拆分為多個小鎖,每個小鎖保護一部分數據,降低線程間的競爭概率。典型代表:ConcurrentHashMap 的分段鎖(Java 7)與 Node 節點級別 CAS + synchronized 組合(Java 8)。

  • Java 7 段鎖:默認 16 個 Segment,在高并發量下,最多允許 16 個線程并行寫入不同段。
  • Java 8 設計:引入 CAS 樂觀鎖、自旋鎖和 synchronized,逐步升級到更重的鎖粒度,減少性能損失。

2.2 無鎖設計(Lock-Free)

通過原子操作(CAS/Compare-And-Swap)實現并發控制,無需阻塞。

  • 核心原語Unsafe.compareAndSwapXXX
  • Atomic 類族AtomicIntegerAtomicLongAtomicReference
  • 高級抽象LongAdderStriped64(內部使用分段累加設計),ConcurrentLinkedQueue(基于 Michael-Scott 算法的無鎖鏈表)。

優點:無阻塞、降低上下文切換開銷;缺點:ABA 問題、CPU 自旋開銷、不易調試。


三、關鍵源碼解讀

3.1 ConcurrentHashMap(Java 8)核心片段

// putVal 方法中使用 CAS + synchronized
if (tab == null || tab.length == 0)tab = resize();
int n = tab.length;
int i = (n - 1) & hash;
Node<K,V> f = tab[i];
if (f == null) {// 空桶位置,使用 CAS 插入if (casTabAt(tab, i, null, newNode(hash, key, value, null)))break;                   
} else if (f.hash == MOVED) {// 擴容過程中,幫助擴容tab = helpTransfer(tab, f);
} else {synchronized (f) {// synchronized 保護鏈表或樹結構插入// 插入或更新邏輯... }
}
  • 先嘗試樂觀 CAS 插入;
  • 失敗后退化到 synchronized 塊,鎖粒度細化到單個桶,避免全表鎖。

3.2 LongAdder 分段累加設計

public class LongAdder extends Striped64 implements Serializable {public void add(long x) {Cell[] as; long b, v; int m;if ((as = cells) != null || !casBase(b = base, b + x)) {boolean uncontended = true;if (as == null || (m = as.length - 1) < 0 || (v = as[getProbe() & m].value) == 0 || !as[getProbe() & m].cas(v, v + x))longAccumulate(x, null, uncontended);}}public long sum() {Cell[] as = cells; long sum = base;if (as != null) {for (Cell a : as)if (a != null)sum += a.value;}return sum;}
}
  • base:針對低并發直接使用 CAS;
  • cells:高并發時分配 Cell 數組,每個線程通過 probe 隨機落到不同槽位,減少沖突。

四、實際應用示例

4.1 高性能并發計數器對比

示例:1000 個線程并發執行一百萬次累加,比較 AtomicLongsynchronizedLongAdder

public class CounterBenchmark {static final int THREADS = 1000;static final int ITER = 1_000_000;public static void testAtomic() {AtomicLong counter = new AtomicLong();runBenchmark(() -> counter.incrementAndGet(), "AtomicLong");}public static void testSync() {long[] counter = {0};runBenchmark(() -> {synchronized (counter) {counter[0]++;}}, "synchronized block");}public static void testAdder() {LongAdder adder = new LongAdder();runBenchmark(adder::increment, "LongAdder");}private static void runBenchmark(Runnable op, String name) {Thread[] threads = new Thread[THREADS];long start = System.nanoTime();for (int i = 0; i < THREADS; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < ITER; j++) op.run();});threads[i].start();}for (Thread t : threads) {try { t.join(); } catch (InterruptedException e) {}}long cost = System.nanoTime() - start;System.out.printf("%s cost: %d ms\n", name, cost / 1_000_000);}public static void main(String[] args) {testAtomic();testSync();testAdder();}
}

運行結果(示例環境):

AtomicLong cost: 450 ms
synchronized block cost: 520 ms
LongAdder cost: 120 ms

4.2 無鎖隊列:ConcurrentLinkedQueue

Queue<Integer> queue = new ConcurrentLinkedQueue<>();
// 多線程并發入隊
IntStream.range(0, 10000).parallel().forEach(queue::offer);
// 多線程并發出隊
IntStream.range(0, 10000).parallel().forEach(i -> queue.poll());
  • 基于 Michael-Scott 算法的無鎖鏈表,入隊出隊均使用 CAS 更新頭尾指針,無阻塞。實測在中等并發場景下吞吐量優于 BlockingQueue。

五、性能特點與優化建議

  1. 綜合策略:對熱點計數場景優先考慮 LongAdder;對 Map/Set 并發訪問使用 ConcurrentHashMap(或自定義分段鎖);需要隊列或鏈表結構,優先采用 ConcurrentLinkedQueue 等無鎖實現。
  2. 線程親和性:盡量減少線程切換,可使用線程池與自定義 ThreadFactory 綁定核心數。
  3. 合理設置分段數:如 LongAdder 或 ConcurrentHashMap 的分段數量,可根據并發度與 CPU 核心數調優。
  4. 監控指標:結合 JMH 或 JVM 自帶的 Flight Recorder (JFR) 進行壓測與監控,定位熱點數據結構。
  5. 避免過度拆分:鎖分離帶來的空間開銷與復雜度提升需權衡,生產環境下先做基準測試。

通過鎖分離與無鎖設計,Java 并發編程的性能可以獲得顯著提升。希望本文能為您的高并發系統優化提供有力指導。

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

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

相關文章

SpringSecurity-spring security單點登錄

在 Spring Boot 中實現 單點登錄&#xff08;SSO, Single Sign-On&#xff09;&#xff0c;通常使用 OAuth2 或 OIDC&#xff08;OpenID Connect&#xff09; 協議來完成。Spring Security 提供了對 OAuth2 和 OIDC 的完整支持&#xff0c;可以輕松集成如 Google、GitHub、Okta…

《前端基礎核心知識筆記:HTML、CSS、JavaScript 及 BOM/DOM》

html 前端三劍客的介紹&#xff1a; HTML:頁面內容的載體 Css&#xff1a;用來美化和指定頁面的顯示效果 JavaScript&#xff1a;頁面顯示的過程中&#xff0c;可以動態改變頁面的內容 重點屬性 type"text"文本輸入 type"password"密碼輸入 <a…

基于vue.js的客戶關系管理系統(crm)的設計與實現(源碼+論文)

相關技術 SSM框架介紹 開發環境&#xff1a; 技術&#xff1a;SSM框架&#xff08;Spring Spring MVC MyBatis&#xff09; 描述&#xff1a; SSM框架是Java Web開發中廣泛使用的流行框架之一。Spring&#xff1a;提供全面的基礎設施支持&#xff0c;管理應用對象&#…

AWS權限異常實時告警系統完整實現指南

概述 本文將詳細介紹如何構建一個基于CloudTrail → S3 → Lambda → SNS → Webhook/Email架構的AWS權限異常實時告警系統。該系統能夠實時監控AWS環境中的權限異常事件,并通過多種方式發送告警通知,幫助企業及時發現和響應安全威脅。 系統架構 ┌───────────…

NIO網絡通信基礎

文章目錄概述一、Socket二、NIO三大組件與事件三、Reactor模式四、NIO通信案例4.1、服務端4.2、客戶端本文為個人學習筆記整理&#xff0c;僅供交流參考&#xff0c;非專業教學資料&#xff0c;內容請自行甄別 概述 前篇中提到&#xff0c;BIO是阻塞的IO&#xff0c;阻塞體現在…

Redis4緩存穿透:布隆過濾器與空對象方案

緩存穿透緩存穿透是指客戶端請求的數據在緩存中和數據庫中都不存在&#xff0c;這樣緩存永遠不會生效&#xff0c;這些請求都會達到數據庫。1)方案1&#xff1a;緩存空對象在緩存中存儲一個空值每次讀取這個空優點&#xff1a;實現簡單&#xff0c;維護方便缺點&#xff1a;造成…

域名WHOIS信息查詢免費API使用指南

本文介紹由接口盒子提供的免費域名WHOIS查詢API服務&#xff0c;幫助開發者快速獲取域名的注冊信息、到期時間、DNS服務器等關鍵數據。 一、接口基本信息 ?功能說明?&#xff1a;查詢頂級域名的WHOIS信息&#xff08;不支持國別域名/中文域名&#xff09;?請求地址?&#…

【18位數據次方提高數據輸出速度】2022-3-9

實在是無法忍受W10輸出數據那么慢W7需要2分鐘輸出數據W10則需要10分鐘完成W7需要3分鐘W10則需要15分鐘完成輸出數據&#xff0c;雖然W10運算速度比W7快很多但是加上輸出速度總體完成時間居然差不多&#xff01;隨著使用數組超過百萬W7數據輸出時間也變長&#xff0c;隨著數組數…

云原生技術與應用-Kubernetes架構原理與集群環境部署

目錄 一.為什么需要kubernetes 1.對于開發人員 2.對于運維人員 二.kubernetes帶來的挑戰 三.kubernetes架構解析 1.master節點的組件 2.node節點包含的組件 3.kubernetes網絡插件 四.kubernetes快速安裝kubernetes集群 1.部署docker環境 2.部署kubernetes集群 五.Metrics-…

百度權重提升技巧分析:從底層邏輯到實戰策略

在搜索引擎優化&#xff08;SEO&#xff09;領域&#xff0c;百度權重始終是網站運營者關注的核心指標之一。它不僅反映了網站在百度搜索中的綜合表現&#xff0c;更直接影響著流量獲取能力與商業價值。然而&#xff0c;百度權重并非百度官方直接公布的數據&#xff0c;而是第三…

模擬數據生成---使用NGS數據模擬軟件VarBen

目錄 1.在BAM文件中根據指定的變異等位基因分數的指定位置或區域隨機選擇read。 2.篩選變異等位基因分數的reads: 3.裝BWA和samtools軟件包(samtools在linux系統中下載過,前文有講過) 4.寫py腳本 5.下載pysam庫模塊 6.下載參考基因組hg38 7.解壓gz 8.建立samtools索引…

Redis-典型應用-分布式鎖

目錄 1.什么是分布式鎖? 2.分布式鎖的實現 3.引入過期時間 4.引入校驗ID 5.引入lua腳本: 6.引入看門狗(watch dog) 7.引入redislock算法: 1.什么是分布式鎖? 在 分布式系統中,會出現多個節點同時訪問同一個公共資源, 此時就需要通過鎖來作互斥控制,避免出現類似于多線程…

Dinky (Mac) 本地開發環境搭建指南

目錄 一、前置條件 二、代碼準備 三、前端環境搭建 1. 安裝Node環境 2. 安裝PNPM 3. 構建前端 四、后端環境搭建 1. 本地編譯依賴 2. 添加必要依賴 3. 啟動后端服務 五、訪問系統 附錄&#xff1a;官方參考 一、前置條件 確保已安裝以下軟件&#xff1a; 軟件要求…

Java Set 集合詳解:從基礎語法到實戰應用,徹底掌握去重與唯一性集合

作為一名 Java 開發工程師&#xff0c;你一定在實際開發中遇到過需要去重、唯一性校驗、快速查找等場景。這時候&#xff0c;Set 集合 就成為你不可或缺的工具。本文將帶你全面掌握&#xff1a;Set 接口的定義與核心方法常見實現類&#xff08;如 HashSet、TreeSet、LinkedHash…

在分布式系統中,如何保證緩存與數據庫的數據一致性?

口訣&#xff1a; 讀多寫少用旁路&#xff0c;先更庫再刪緩存&#xff1b; 強一致選寫透&#xff0c;緩存代理更庫走&#xff1b; 性能優先用寫回&#xff0c;異步批量有風險&#xff1b; 高并發加雙刪&#xff0c;延遲兜底防舊殘&#xff1b; 強一致用鎖串&#xff0c;并發雖低…

【洛谷P1417】烹調方案 題解

題目大意 一共有 nnn 件食材&#xff0c;每件食材有三個屬性&#xff0c;aia_iai?&#xff0c;bib_ibi? 和 cic_ici?&#xff0c;如果在 ttt 時刻完成第 iii 樣食材則得到 ai?tbia_i-t\times b_iai??tbi? 的美味指數&#xff0c;用第 iii 件食材做飯要花去 cic_ici? 的…

vue svg實現一個環形進度條組件

svg實現一個環形進度條設計初衷&#xff1a;本來想直接使用element的進度條組件的&#xff0c;但是好多屬性都沒有辦法控制。 UI設計的圖如下&#xff0c;需要控制未完成和已完成的顏色&#xff0c;端點的形狀改為普通的butt 所以使用svg實現了一個環形進度條組件element組件設…

02 51單片機之LED閃爍

文章目錄1、單片機1-1、簡介1-2、應用場景2、51單片機2-1、背景2-2、主要品牌及其產品2-3、基本組成2-4、命名規則3、單片機內部結構3-1、單片機內部結構圖3-2、單片機內部結構3-3、單片機內部管腳圖3-4、單片機最小系統3-5、開發板介紹4、點亮LED4-1、新建工程4-1-1、創建工程…

Typecho博客集成算術驗證碼防御垃圾評論實戰指南

文章目錄 Typecho實現算術驗證碼防御機器人垃圾評論的完整方案 背景與問題分析 技術方案設計 系統架構 技術選型 核心實現步驟 1. 創建驗證碼生成函數 2. 修改評論表單模板 3. 添加AJAX刷新功能 4. 創建驗證碼刷新接口 5. 添加評論提交驗證 安全增強措施 1. 防止暴力破解 2. 增…

clonezilla 導出自動化恢復iso

clonezilla 下載及U盤工具下載 clonezilla rufus U盤寫入工具ventoy U盤工具downloaddownloaddownload clonezilla 備份&#xff0c;連貫上一篇文章參考 Choose Clonezilla live (VGA 800x600) Wait for it to complete Language selection Keyboard Settings Select Mode …