“多線程修路:當count++變成災難現場”

1.現象

當我們操作一個線程池的時候,可能需要去計數,也就是統計count,那我們這里有一個疑問,會不會產生線程安全問題?

毫無疑問絕對會有線程安全問題。在線程池環境中,多個線程并發訪問和修改一個共享的 count 變量(例如通過 count++count = count + 1),如果不加鎖或使用其他同步機制,會導致結果不可預測和不正確。

2.就像我們現在的這樣

在這里插入圖片描述

根本原因分析:

  1. 非原子性count++ 操作被拆分為 3 個獨立步驟
  2. 時間窗口:在讀取和寫入之間存在競爭窗口期
  3. 缺乏可見性:線程 B 看不到線程 A 的中間結果
  4. 寫覆蓋:后寫入的線程覆蓋了前一線程的結果

原因如下:

  1. 非原子性操作 (count++):

    • count++ 這樣看似簡單的操作,在底層通常需要多個步驟:
      1. 讀取:從內存中讀取 count 的當前值到線程的寄存器或本地緩存。
      2. 修改:在寄存器/緩存中將讀取到的值加 1。
      3. 寫入:將修改后的新值寫回內存中的 count 變量。
    • 這些步驟本身不是原子操作(不可分割的操作)。多個線程完全有可能交錯執行這些步驟。
  2. 競爭條件 (Race Condition):

    • 假設 count 初始值為 0。
    • 線程 A 執行步驟 1,讀取到 count = 0
    • 線程 B 執行步驟 1,也讀取到 count = 0(因為線程 A 還沒來得及寫回)。
    • 線程 A 執行步驟 2,計算 0 + 1 = 1
    • 線程 B 執行步驟 2,計算 0 + 1 = 1
    • 線程 A 執行步驟 3,將 1 寫入 count,內存中 count 變為 1。
    • 線程 B 執行步驟 3,將 1 寫入 count,內存中 count 還是 1(覆蓋了線程 A 的結果)。
    • 結果:兩個線程都執行了 count++,但最終 count 的值是 1 而不是預期的 2。這就是經典的“丟失更新”問題。
  3. 可見性問題 (Visibility):

    • 現代 CPU 架構擁有多級緩存(L1, L2, L3)。每個線程可能在自己的 CPU 核心的緩存中操作 count 的副本。
    • 當一個線程修改了它緩存中的 count 值,這個修改不會立即對其他線程的緩存可見。
    • 線程 B 可能仍然看到 count 的舊值(比如 0),即使線程 A 已經把它加到了 1(但新值還在線程 A 的緩存里,沒刷回主內存或線程 B 的緩存沒更新)。
    • 這也會導致線程 B 基于過時的值進行計算,最終結果錯誤。

后果:

  • 最終 count 的值會小于實際所有線程執行 count++ 操作的次數總和。丟失更新的次數越多,差距越大。
  • 程序行為不可預測,結果每次運行都可能不同(取決于線程調度的時機)。

3.如何解決?

必須使用同步機制來保證對 count 的訪問和修改是原子性的,并且修改對其他線程是可見的:

  1. 使用 synchronized 關鍵字 (鎖):

    private int count = 0;
    private final Object lock = new Object(); // 專門用作鎖的對象public void increment() {synchronized (lock) { // 獲取鎖count++; // 在鎖保護的臨界區內安全地遞增} // 釋放鎖
    }
    
    • 優點:簡單直觀,適用于復雜的同步邏輯。
    • 缺點:性能開銷相對較大(獲取/釋放鎖、線程阻塞/喚醒)。
  2. 使用 ReentrantLock:

    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();public void increment() {lock.lock(); // 顯式獲取鎖try {count++;} finally {lock.unlock(); // 確保在finally塊中釋放鎖}
    }
    
    • 優點:比 synchronized 更靈活(如可嘗試獲取鎖、可中斷鎖、公平鎖等)。
    • 缺點:需要手動管理鎖的獲取和釋放,否則容易死鎖;性能開銷與 synchronized 接近或略優/劣(取決于場景和 JDK 版本)。
  3. 使用原子類 (java.util.concurrent.atomic) - 強烈推薦用于計數器:

    private final AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet(); // 原子地遞增并返回新值// 或者 count.getAndIncrement(); // 原子地遞增并返回舊值
    }
    
    • 優點:性能最高!底層使用 CPU 提供的 CAS (Compare-And-Swap) 指令實現無鎖并發。特別適合簡單的計數器場景。

    • 缺點:只能用于特定的原子操作(遞增、遞減、加法、比較并設置等)。對于需要保護多個變量或復雜邏輯的復合操作,原子類可能不夠用,需要用鎖。

    解決方案對比:

    方法原理性能影響適用場景
    synchronized互斥鎖高 (上下文切換)復雜同步邏輯
    AtomicIntegerCAS 指令低 (CPU 原語)簡單計數器
    ReentrantLock可重入鎖中 (優于 synchronized)需要靈活控制的場景

4.結論:

在線程池(或任何多線程環境)中,對共享可變狀態(如你的 count)進行并發修改,必須使用適當的同步機制(鎖或原子類)。不采取任何同步措施必然會導致線程安全問題,使 count 的值不可靠。

對于簡單的計數器場景,優先考慮 AtomicIntegerAtomicLong,它們提供了最佳的性能和簡潔性。

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

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

相關文章

GaussDB null的用法

1 null的定義null 空值代表丟失的未知數據。 默認情況下,表列可以保存 null 值。 本章解釋 is null 和 is not null 操作符。2 null值的贅述如果表中的列是可選的,那么我們可以插入一個新記錄或更新一個現有記錄,而無 需向列添加一個值。這意…

智慧農業新圖景:物聯網如何精準守護作物生長?

在傳統農業生產模式下,農民往往憑借經驗判斷作物生長需求,灌溉、施肥缺乏精準性,導致水資源浪費、土壤板結、作物產量與品質難以提升等問題。加之氣候變化無常,極端天氣頻發,給農業生產帶來諸多不確定性,傳…

[ComfyUI] -入門2- 小白零基礎搭建ComfyUI圖像生成環境教程

AI圖像生成已經成為AIGC(人工智能生成內容)領域的重要組成部分,而ComfyUI作為一款可視化的Stable Diffusion工作流工具,以其模塊化、高度自由化的特點吸引了越來越多創作者的關注。本文將手把手教你如何在Windows系統下,從零搭建屬于自己的ComfyUI圖像生成環境。 一、Comf…

java設計模式 -【單例模式】

單例模式的定義 單例模式(Singleton Pattern)是一種創建型設計模式,確保一個類只有一個實例,并提供一個全局訪問點。常用于需要控制資源或共享狀態的場景,例如數據庫連接、日志記錄器等 單例模式的實現方式 餓漢式&…

Flink 自定義類加載器和子優先類加載策略

子類優先加載Flink 默認采用了子優先(Child-First)的類加載策略來加載用戶代碼,以解決潛在的依賴沖突問題。我們可以通過源碼來證明這一點。ChildFirstClassLoader 的實現Flink 中負責實現“子優先”加載邏輯的核心類是 ChildFirstClassLoade…

Nginx 安全加固:如何阻止 IP 直接訪問,只允許域名訪問

在部署網站或 Web 應用時,我們通常會通過域名來訪問服務。然而,有時用戶可能會嘗試直接使用服務器的 IP 地址來訪問,這不僅可能繞過我們的域名特定配置(如 SSL 證書、重定向規則等),還可能導致不必要的安全風險或管理混亂。本文將介紹如何配置 Nginx,使其在通過 IP 地址…

服務端處于 TIME_WAIT 狀態的 TCP 連接,收到相同四元組的 SYN 后會發生什么?詳解

文章目錄一、先判斷 SYN 是否合法1、開啟「時間戳」機制1.1、合法 SYN1.2、非法 SYN2、關閉「時間戳」機制1.1、合法 SYN1.2、非法 SYN二、收到合法 SYN三、收到非法 SYN一、先判斷 SYN 是否合法 1、開啟「時間戳」機制 1.1、合法 SYN 客戶端的 SYN「序列號」比服務端「期望…

數字化轉型:一文讀懂從單系統到智能架構(業務、應用、數據、技術架構)的跨越

在數字化浪潮席卷全球的今天,企業正經歷從 “單系統孤島” 到 “智能架構協同” 的范式革命。智能架構以業務敏捷化、應用服務化、數據價值化、技術云原生化為核心特征,通過四個維度的架構升級,破解傳統 IT 系統的效率瓶頸,支撐企…

AUTOSAR進階圖解==>AUTOSAR_SRS_Transformer

AUTOSAR Transformer 詳解 基于AUTOSAR 4.4.0標準的Transformer模塊分析與說明目錄 1. Transformer概述 1.1 Transformer的作用1.2 Transformer的基本特性 2. Transformer架構 2.1 整體架構2.2 類層次結構 3. Transformer類型 3.1 SOME/IP Transformer3.2 COM Based Transform…

【算法專題訓練】05、最大單詞長度乘積

1、題目信息 https://leetcode.cn/problems/aseY1I/description/ 給定一個字符串數組 words,請計算當兩個字符串 words[i] 和 words[j] 不包含相同字符時,它們長度的乘積的最大值。假設字符串中只包含英語的小寫字母。如果沒有不包含相同字符的一對字符串…

Tenable 利用 AI 升級漏洞評級系統,提升風險優先級排序能力

網絡安全公司 Tenable Holdings Inc. 今日宣布對其漏洞優先級評級系統(Vulnerability Priority Rating,VPR)進行人工智能驅動的升級,旨在幫助機構更準確地識別和應對最具威脅性的漏洞。從60%到1.6%的精準聚焦Tenable VPR 系統于20…

安全插座項目規劃書

安全插座項目規劃書 一、項目概述 本項目旨在設計并開發一款安全插座,通過集成多種安全保護功能,有效預防因電氣故障引發的安全問題,如過載、短路、漏電等,為用戶提供更加可靠的用電環境。 二、技術架構 (一&#xff0…

Logcat日志分析

1. AndroidRuntime關鍵字(跟整個系統代碼相關) 一、AndroidRuntime的核心作用 AndroidRuntime是Android系統負責啟動和運行應用程序的核心組件,當應用因未處理的異常(如空指針、數組越界等)導致崩潰時,Andr…

Apache Ranger 權限管理

編譯 mvn install package -DskipTests -Dfast -Drat.skiptrue -Dmaven.test.skiptrue -Dcheckstyle.skiptrue -Denforcer.skiptrueinstall.properties PYTHON_COMMAND_INVOKERpython#DB_FLAVORMYSQL|ORACLE|POSTGRES|MSSQL|SQLA DB_FLAVORMYSQL ## # Location of DB client l…

tailscale+GitLab

1. 查看當前 LFS 的遠程地址 bash 復制 git lfs env | grep Endpoint 你會看到類似: Endpointhttp://192.168.3.36/makeup/classicparking.git/info/lfs (authbasic) 2. 修改 LFS 的遠程地址 使用以下命令將 LFS 的地址改為 http://100.125.163.56&#xff1…

微信通話自動錄音器

—————【下 載 地 址】——————— 【?本章下載一】:https://pan.xunlei.com/s/VOVvLpQuRxYadClkxTGwO2OnA1?pwdvind# 【?本章下載二】:https://pan.xunlei.com/s/VOVvLpQuRxYadClkxTGwO2OnA1?pwdvind# 【百款黑科技】:https://uc…

05.原型模式:從影分身術到細胞分裂的編程藝術

目錄序幕:當復制對象成為戰略需求一、原型工廠的核心裝備庫1.1 Java原生的淺克隆術二、深度克隆的煉金法則2.1 手工克隆大法(硬核派)2.2 序列化克隆術(魔法派)三、原型模式的工業級裝配3.1 原型注冊管理局3.2 Spring框…

[NLP]如何在 Synopsys VCS 仿真腳本中處理多個 UPF 文件的加載

如何在 Synopsys VCS 仿真腳本中處理多個 UPF 文件的加載 摘要:我將詳細解釋在 Synopsys VCS(VCS)模擬腳本中如何處理多個 UPF 文件的加載,包括原理、命令選項、示例腳本以及注意事項。這基于 VCS 的 native low power verification 支持(IEEE 1801 UPF 標準)。如…

DNF: Decouple and Feedback Network for Seeing in the Dark

DNF:用于暗光視覺的解耦與反饋網絡 摘要 RAW 數據的獨特屬性在低光照圖像增強方面展現出巨大潛力。然而,現有架構在單階段和多階段方法中的固有局限性限制了其性能。跨兩個不同域(噪聲到干凈和 RAW 到 sRGB)的混合映射&#xff0c…

論文精讀《Frequency domain watermarking: An overview》

1. 數字水印技術基礎概念與發展背景 數字水印技術作為信息隱藏領域的核心分支,其發展歷程可以追溯到20世紀90年代中期計算機網絡和信息技術的快速發展時期。隨著大量版權作品以數字文件形式存在,電子出版逐漸普及,傳統的版權保護方法面臨前所未有的挑戰。數字水印技術應運而…