并發編程——累加器

目錄

1 AtomicLong

1.1 核心功能

1.2 實現原理:

(1)基于 Unsafe 的底層操作

(2) volatile字段的內存可見性

(3)CAS 操作與 ABA 問題

1.3 性能分析

1.4 使用場景

2 LongAdder

核心設計原理

1 分段存儲

2 分散更新策略

3.處理高競爭


1 AtomicLong

AtomicLong 是一個基于 CAS操作的原子類,用于在多線程環境下對 long 類型變量進行無鎖的原子性操作。它通過底層的 Unsafe 類實現高效的原子更新,解決傳統 synchronized 關鍵字帶來的性能開銷問題。

1.1 核心功能

AtomicLong 支持以下原子操作:

方法

功能

實現原理

add(long delta)

原子性地將變量增加 delta

CAS 操作

incrementAndGet()

原子性自增 1 并返回新值

add(1L)

decrementAndGet()

原子性自減 1 并返回新值

add(-1L)

getAndAdd(long delta)

原子性增加 delta

并返回原值

CAS 操作

getAndSet(long newValue)

原子性設置新值并返回原值

CAS 操作

compareAndSet(long expect, long update)

原子性將值從 expect

更新為 update

(如果相等)

CAS 操作

get()

獲取當前值(非原子,但保證可見性)

直接讀取 value 字段

1.2 實現原理:

(1)基于 Unsafe 的底層操作

AtomicLong 的所有原子方法均通過 sun.misc.Unsafe 類的底層原生指令實現,例如:

objectFieldOffset:獲取long value字段在對象內存中的偏移量

getAndAddLong:通過CPU的CAS指令(如 cmpxchgq)原子性更新內存中的值。

(2) volatile字段的內存可見性

AtomicLongvalue 字段聲明為 volatile ,確保一個線程的修改對其它線程可見:

(3)CAS 操作與 ABA 問題

  • CAS 操作

CAS(Compare-And-Swap)包含三個步驟:

  1. 比較:讀取內存中的舊值 expect
  2. 交換:如果舊值等于 expect,則將新值 update 寫入內存;否則不操作。
  3. 返回結果:返回內存中的舊值。
  • ABA 問題
  • 場景:變量從 A → B → A,此時 compareAndSet(A, C) 會錯誤地認為值未變,導致更新失敗。
  • 解決方案
    • AtomicStampedReference:引入版本戳(stamp)標記變量的修改次數,解決 ABA 問題。
    • LongAdder:通過分散更新壓力避免單一變量的頻繁 CAS 沖突。

1.3 性能分析

優勢

  • 無鎖操作:避免線程阻塞和上下文切換,性能優于 synchronized
  • 讀寫高效:get() 方法是非原子的,但保證內存可見性,讀取速度極快。
  • 適用場景:低到中等并發場景,如計數器、單變量累加器。

局限性

  • 高并發瓶頸:當多個線程激烈競爭同一變量時,CAS 失敗次數劇增,導致自旋開銷(spin-wait)。
  • ABA 問題:需額外處理或改用 AtomicStampedReference

1.4 使用場景

低競爭環境:如單機多線程的計數器、序列號生成。

需要強原子性保證:如銀行賬戶扣款、分布式鎖的版本控制。

2 LongAdder

設計目標LongAdder是Java 8引入的原子類,屬于 java.util.concurrent.atomic 包,專為高并發場景下的累加操作優化。它的核心目標是解決AtomicLong 在及極高并發下的性能瓶頸——通過分散壓力來減少線程間的CAS沖突。

核心設計原理

1 分段存儲

  • cells數組: LongAdder維護一個動態增長的long[]cells數組,每個元素成為一個cell,用于存儲部分累加值。
  • base變量:所有cell之外的累加值存儲在base中,默認情況下,單個線程的增量優先base,當base發生競爭時,才會分配新的cell。

2 分散更新策略

  1. 優先更新 base(①):
    1. cells 未初始化(null),或通過 casBase 成功將 base 加上 x,直接返回。casBaseStriped64 提供的原子操作,用于更新 base
  2. 處理 cells 分段(②-④):
    1. ?哈希索引計算getProbe() 返回與當前線程綁定的哈希值(通過 ThreadLocalRandom 生成),并與數組長度掩碼按位與,得到目標 cell 的索引。
    2. CAS 更新 cell:若目標 cell 為空,通過 casCell 初始化為新值;否則嘗試原子性增加 cell 的值。
    3. 競爭標記:若 CAS 失敗(uncontended = false),表示存在線程競爭。

3.處理高競爭

調用 longAccumulate 方法,可能觸發以下操作:

  • 動態擴容:若 cells 數組過小,倍增其大小并將 base 值分布到新 cell 中。
  • 批量寫入:將當前線程的增量暫存到臨時變量,直到找到可寫入的 cell。
public void add(long x) {Cell[] as; long b, v; int m; Cell a;if ((as = cells) != null || !casBase(b = base, b + x)) { // ① 優先嘗試更新 baseboolean uncontended = true;if (as == null || (m = as.length - 1) < 0 || // ② 處理未初始化或空數組(a = as[getProbe() & m]) == null ||     // ③ 計算哈希索引并獲取目標 cell!(uncontended = a.cas(v = a.value, v + x))) { // ④ CAS 更新 celllongAccumulate(x, null, uncontended); // ⑤ 處理競爭,觸發動態擴容}}
}

sum方法:返回base值和cells數組的總和

public long sum() {Cell[] as = cells; Cell a;long sum = base;if (as != null) {for (int i = 0; i < as.length; ++i) {if ((a = as[i]) != null)sum += a.value;}}return sum;
}

reset方法:重置變量,使總和保持為零。

此方法可能是創建新 adder 的有用替代方法,但僅在沒有并發更新時有效。由于此方法本質上是 racy,因此僅當已知沒有線程同時更新時,才應使用它。

public void reset() {Cell[] as = cells; Cell a;base = 0L;if (as != null) {for (int i = 0; i < as.length; ++i) {if ((a = as[i]) != null)a.value = 0L;}}
}

sumThenReset方法:返回當前總和后清零,適用于離線統計場景

實際上等效于 sum 后跟 reset。例如,在多線程計算之間的 static points 期間,此方法可能適用。如果存在與此方法并發的更新, 則不能保證 返回的值是重置之前出現的最終值。

public long sumThenReset() {Cell[] as = cells; Cell a;long sum = base;base = 0L;if (as != null) {for (int i = 0; i < as.length; ++i) {if ((a = as[i]) != null) {sum += a.value;a.value = 0L;}}}return sum;
}

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

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

相關文章

大模型管理工具:LLaMA-Factory

目錄 一、安裝與環境配置 二、?啟動 Web 界面 三、數據準備 四、模型訓練 五、模型評估 七、模型導出 八、API服務部署 LLaMA-Factory 是一個開源的大語言模型&#xff08;LLM&#xff09;微調框架&#xff0c;旨在簡化大規模模型的訓練、微調和部署流程。它支持多種主…

推流項目的ffmpeg配置和流程重點總結一下

ffmpeg的初始化配置&#xff0c;在合成工作都是根據這個ffmpeg的配置來做的&#xff0c;是和成ts流還是flv&#xff0c;是推動遠端還是保存到本地&#xff0c; FFmpeg 的核心數據結構&#xff0c;負責協調編碼、封裝和寫入操作。它相當于推流的“總指揮”。 先來看一下ffmpeg的…

大語言模型從理論到實踐(第二版)-學習筆記(緒論)

大語言模型的基本概念 1.理解語言是人工智能算法獲取知識的前提 2.語言模型的目標就是對自然語言的概率分布建模 3.詞匯表 V 上的語言模型&#xff0c;由函數 P(w1w2 wm) 表示&#xff0c;可以形式化地構建為詞序列 w1w2 wm 的概率分布&#xff0c;表示詞序列 w1w2 wm…

strace工具的交叉編譯

1、下載源碼 git clone https://github.com/strace/strace.git cd strace 2、運行 bootstrap 腳本&#xff08;如果需要&#xff09; 如果源碼中沒有 configure 腳本&#xff0c;運行以下命令生成&#xff1a; ./bootstrap 3. 配置編譯參數 運行 configure 腳本&#xff…

Vue 3 組件庫持續集成 (CI) 實戰:GitHub Actions 自動化測試與 Storybook 文檔構建 - 構建高效可靠的組件庫 CI 流程

引言 歡迎再次回到 Vue 3 + 現代前端工程化 系列技術博客! 在昨天的第十篇博客中,我們深入學習了代碼覆蓋率分析,掌握了利用 Jest 代碼覆蓋率報告提升單元測試有效性的方法,進一步鞏固了組件庫的質量防線。 今天,我們將邁向 自動化流程 的構建,聚焦于 持續集成 (Continu…

無穿戴動捕數字人互動方案 | 暢享零束縛、高沉浸的虛實交互體驗

在數字化浪潮席卷而來的當下&#xff0c;虛擬人互動體驗正逐漸成為各領域的新寵。長久以來&#xff0c;虛擬人驅動主要依靠穿戴式動作捕捉設備&#xff0c;用戶需要通過佩戴傳感器或標記點來實現動作捕捉。然而&#xff0c;隨著技術的不斷突破&#xff0c;一種全新的無穿戴動作…

03 HarmonyOS Next儀表盤案例詳解(二):進階篇

溫馨提示&#xff1a;本篇博客的詳細代碼已發布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下載運行哦&#xff01; 文章目錄 前言1. 響應式設計1.1 屏幕適配1.2 彈性布局 2. 數據展示與交互2.1 數據卡片渲染2.2 圖表區域 3. 事件處理機制3.1 點擊事件處理3.2 手勢…

python-leetcode-統計構造好字符串的方案數

2466. 統計構造好字符串的方案數 - 力扣&#xff08;LeetCode&#xff09; 這個問題可以用**動態規劃&#xff08;DP&#xff09;**來解決&#xff0c;思路如下&#xff1a; 思路 1. 定義 DP 數組 設 dp[i] 表示長度為 i 的好字符串的個數。 2. 狀態轉移方程 我們可以在 dp…

MySQL------存儲引擎和用戶和授權

9.存儲引擎 1.兩種引擎 MyISAM和InnoDB 2.兩種區別 1.事務&#xff1a; MyISAM不支持事務 2.存儲文件: innodb : frm、ibd MyISAM: frm、MYD、MYI 3.數據行鎖定: MyISAM不支持 4.全文索引: INNODB不支持&#xff0c;所以MYISAM做select操作速度很快 5.外鍵約束: MyISAM…

題海拾貝:P9241 [藍橋杯 2023 省 B] 飛機降落

Hello大家好&#xff01;很高興我們又見面啦&#xff01;給生活添點passion&#xff0c;開始今天的編程之路&#xff01; 我的博客&#xff1a;<但凡. 我的專欄&#xff1a;《編程之路》、《數據結構與算法之美》、《題海拾貝》 歡迎點贊&#xff0c;關注&#xff01; 1、題…

刪除有序數組中的重復項(js實現,LeetCode:26)

給你一個 非嚴格遞增排列 的數組 nums &#xff0c;請你原地刪除重復出現的元素&#xff0c;使每個元素只出現一次&#xff0c;返回刪除后數組的新長度。元素的相對順序應該保持一致。然后返回 nums 中唯一元素的個數。 考慮 nums 的唯一元素的數量為 k &#xff0c;你需要做以…

3-9 WPS JS宏單元格復制、重定位應用(拆分單表到多表)

************************************************************************************************************** 點擊進入 -我要自學網-國內領先的專業視頻教程學習網站 *******************************************************************************************…

大白話react第十六章React 與 WebGL 結合的實戰項目

大白話react第十六章React 與 WebGL 結合的實戰項目 1. 項目簡介 React 是一個構建用戶界面的強大庫&#xff0c;而 WebGL 則允許我們在網頁上實現高性能的 3D 圖形渲染。將它們結合起來&#xff0c;我們可以創建出炫酷的 3D 網頁應用&#xff0c;比如 3D 產品展示、虛擬場景…

【AI賦能】AI 工具生成視頻教材:從創意到成品的全流程指南

AI 工具生成視頻教材&#xff1a;從創意到成品的全流程指南 目標 通過本教材&#xff0c;您將學會如何利用 AI 工具&#xff08;Grok、Sora、Speechify 和 CapCut&#xff09;生成一個完整的視頻&#xff0c;包括腳本生成、視頻片段制作、字幕添加、音頻生成以及最終剪輯合成…

C/C++藍橋杯算法真題打卡(Day2)

一、面試題 08.01. 三步問題 - 力扣&#xff08;LeetCode&#xff09; 算法代碼&#xff1a; class Solution { public:const int MOD 1e9 7;int waysToStep(int n) {// 1. 創建 dp 表// 2. 初始化// 3. 填表// 4. 返回// 處理邊界情況if (n 1 || n 2)return n;if (n 3)r…

騰訊云物聯網平臺(IoT Explorer)設備端使用

1、直接看圖流程 2、跑起來demo,修改產品id,設備名稱,設備秘鑰。 3、連接部分 4、修改默認地址和端口 sdk里面的地址默認是帶著產品ID拼接的,咱們現在中鐵沒有泛域名解析,要改下這里。把+productID都去掉,然后地址里的.也去掉。

GStreamer —— 2.13、Windows下Qt加載GStreamer庫后運行 - “教程13:播放控制“(附:完整源碼)

運行效果(音頻) 簡介 上一個教程演示了GStreamer工具。本教程介紹視頻播放控制。快進、反向播放和慢動作都是技術 統稱為 Trick Modes&#xff0c;它們都有一個共同點 修改 Normal playback rate。本教程介紹如何實現 這些效果并在交易中添加了幀步進。特別是&#xff0c;它 顯…

Dify+DeepSeek | Excel數據一鍵可視化(創建步驟案例)(echarts助手.yml)(文檔表格轉圖表、根據表格繪制圖表、Excel繪制圖表)

Dify部署參考&#xff1a;Dify Rag部署并集成在線Deepseek教程&#xff08;Windows、部署Rag、安裝Ragan安裝、安裝Dify安裝、安裝ollama安裝&#xff09; DifyDeepSeek - Excel數據一鍵可視化&#xff08;創建步驟案例&#xff09;-DSL工程文件&#xff08;可直接導入&#x…

vscode mac版本 配置git

首先使用 type -a git查看git的安裝目錄 然后在vscode中找到settings配置文件&#xff0c;修改git.path

JVM與性能調優詳解

以下是關于 JVM與性能調優 的詳細解析&#xff0c;結合理論、實踐及常見問題&#xff0c;分多個維度展開&#xff1a; 一、JVM性能調優的核心目標 性能調優的核心目標是通過優化內存管理、垃圾回收&#xff08;GC&#xff09;策略和線程管理&#xff0c;實現以下平衡&#xff…