JAVAEE之多線程進階(2)_ CAS概念、實現原理、ABA問題及解決方案

前言

?在并發編程時,常常會出現線程安全問題,那么如何保證原子性呢?常用的方法就是加鎖。在Java語言中可以使用 Synchronized和CAS實現加鎖效果。
?Synchronized關鍵字保證同步的,這會導致有鎖,但是鎖機制存在以下問題:

  1. 在多線程競爭下,加鎖、釋放鎖會導致比較多的上下文切換和調度延時,引起性能問題。

  2. 一個線程持有鎖會導致其它所有需要此鎖的線程掛起。

  3. 如果一個優先級高的線程等待一個優先級低的線程釋放鎖會導致優先級倒置,引起性能風險。

而volatile是不錯的機制,但是volatile不能保證原子性。因此對于同步最終還是要回到鎖機制上來。
?獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖,會導致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。而另一個更加有效的鎖就是樂觀鎖。所謂樂觀鎖就是,每次不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。樂觀鎖用到的機制就是CAS,Compare and Swap


一、什么是CAS?

1.1 概念:

?CAS全稱Compare and swap,字面意思:”比較并交換“,它是一條 CPU 并發原語,用于判斷內存中某個值是否為預期值,如果是則更改為新的值,這個過程是原子的。

1.2 實現步驟

具體步驟如下所示:

  1. 一個初始值變量V,值為5;一開始先讀取V實際內存中的值賦值給E。
  2. 比如我們需要給最原始的V+1操作,那么此時用E+1來進行操作(這是防止V在其他線程已經被改變),這樣完成了U=E+1的操作。
  3. 判斷E和V的值是否一致,如果一致則證明在以上操作過程中V沒有被其他線程改變則將U的值賦值給V,如果不一致那V就被其他改變了,這樣給U的+1操作就不成立,返回當前的V。
    在這里插入圖片描述

1.3 CAS 偽代碼

boolean CAS(address, expectValue, swapValue) {if (&address == expectedValue) {&address = swapValue;return true;}return false;
}

當多個線程同時對某個資源進行CAS操作,只能有一個線程操作成功,但是并不會阻塞其他線程,其他線程只會收到操作失敗的信號。

1.4 實現自旋鎖

基于 CAS 實現更靈活的鎖,獲取到更多的控制權。

public class SpinLock {private Thread owner = null;public void lock(){// 通過 CAS 看當前鎖是否被某個線程持有.// 如果這個鎖已經被別的線程持有, 那么就自旋等待.// 如果這個鎖沒有被別的線程持有, 那么就把 owner 設為當前嘗試加鎖的線程.while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}
}

二、CAS中的問題

2.1 ABA問題

?ABA 是 CAS 操作的一個經典問題,假設有一個變量初始值為 A,修改為 B,然后又修改為 A,這個變量實際被修改過了,但是 CAS 操作可能無法感知到。
?假設存在兩個線程 t1 和 t2,有一個共享變量 num,初始值為 A。接下來, 線程 t1 想使用 CAS 把 num 值改成 Z, 那么就需要

  1. 先讀取 num 的值, 記錄到 oldNum 變量中;
  2. 使用 CAS 判定當前 num 的值是否為 A, 如果為 A, 就修改成 Z.

但是, 在 t1 執行這兩個操作之間,t2 線程可能把 num 的值從 A 改成了 B,又從 B 改成了 A。
在這里插入圖片描述

?如果是整形還好,不會影響最終結果,但如果是對象的引用類型包含了多個變量,引用沒有變實際上包含的變量已經被修改,這就會造成大問題

2.2 ABA問題帶來的BUG

大部分的情況下,t2 線程這樣的一個反復橫跳改動,對于 t1 是否修改 num 是沒有影響的,但是不排除一些特殊情況。

我們接下來舉一個銀行取款大的例子:
假設 小明 有 100 存款,小明想從 ATM 取 50 塊錢。取款機創建了兩個線程, 并發的來執行 -50 操作。我們期望一個線程執行 -50 成功,另一個線程 -50 失敗。如果使用 CAS 的方式來完成這個扣款過程就可能出現問題

正常過程:

  1. 存款 100,線程1 獲取到當前存款值為 100,期望更新為 50; 線程2 獲取到當前存款值為 100, 期望更新為 50;
  2. 線程1 執行扣款成功, 存款被改成 50. 線程2 阻塞等待中;
  3. 輪到線程2 執行了,發現當前存款為 50, 和之前讀到的 100 不相同, 執行失敗。

異常的過程

  1. 存款 100,線程1 獲取到當前存款值為 100,期望更新為 50; 線程2 獲取到當前存款值為 100,期望更新為 50;
  2. 線程1 執行扣款成功,存款被改成 50,線程2 阻塞等待中;
  3. 線程2 執行之前,小明的朋友正好給小明轉賬 50,賬戶余額變成 100;
  4. 輪到線程2 執行了,發現當前存款為 100,和之前讀到的 100 相同,再次執行扣款操作。
    這個時候, 扣款操作被執行了兩次! 都是 ABA 問題導致的結果。

2.3 ABA解決方案

給要修改的值,引入版本號,在 CAS 比較數據當前值和舊值的同時,也要比較版本號是否符合預期。

  1. CAS 操作在讀取舊值的同時,也要讀取版本號。
  2. 真正修改的時候,
    如果當前版本號和讀到的版本號相同, 則修改數據, 并把版本號 +1;
    如果當前版本號高于讀到的版本號,就操作失敗(認為數據已經被修改過了)。

我們依然舉一個銀行取款的例子:

為了解決 ABA 問題, 給余額搭配一個版本號, 初始設為 1:

  1. 存款 100, 線程1 獲取到 存款值為 100,版本號為 1,期望更新為 50; 線程2 獲取到存款值為 100,版本號為 1,期望更新為 50。
  2. 線程1 執行扣款成功,存款被改成 50,版本號改為2。線程2 阻塞等待中。
  3. 在線程2 執行之前, 小明的朋友正好給小明轉賬 50, 賬戶余額變成 100, 版本號變成3.
  4. 輪到線程2 執行了,發現當前存款為 100,和之前讀到的 100 相同, 但是當前版本號為 3,之前讀 到的版本號為 1,版本小于當前版本, 認為操作失敗。

總結

講解下自己理解的 CAS 機制

?全稱 Compare and swap, 即 “比較并交換”, 相當于通過一個原子的操作, 同時完成 “讀取內存, 比較是否相等, 修改內存” 這三個步驟. 本質上需要 CPU 指令的支撐。

ABA問題如何解決

?給要修改的數據引入版本號, 在 CAS 比較數據當前值和舊值的同時,也要比較版本號是否符合預期。如果發現當前版本號和之前讀到的版本號一致,就真正執行修改操作,并讓版本號自增;如果發現當前版本號比之前讀到的版本號大, 就認為操作失敗。

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

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

相關文章

判斷GIF類型并使用ImageDecoder解析GIF圖

一、判斷是否為GIF圖片類型 在JavaScript中,判斷用戶上傳的文件是否為GIF文件類型時,通常可以通過檢查文件的type屬性或文件的拓展名來判斷,但是由于文件拓展名可以輕易被用戶修改,type屬性是由瀏覽器根據文件拓展名猜測得出的&a…

douyin-vue:使用Vue3、Pinia和Vite5打造高度還原的抖音仿制項目

一:引言 在前端技術日新月異的今天,Vue.js作為一款流行的前端框架,不斷吸引著開發者的目光。最近,GitHub上出現了一個備受矚目的項目——douyin-vue,這是一個基于Vue3、Pinia和Vite5的移動端短視頻項目,旨…

[解決]windows mysql8.0.x誤刪除root,解決辦法

1. 停止mysql服務 2. 以管理員身份打開命令窗口,進入到mysql安裝位置的bin目錄下 3. 輸入 mysqld --console --skip-grant-tables --shared-memory 注意:a. 很多解決辦法是輸入mysqld --skip-grant-tables,這在mysql8.0之后的版本已經不在…

ASPICE標準:汽車軟件與嵌入式系統開發的黃金準則-亞遠景

在高度信息化的現代社會,汽車行業的發展已遠超過傳統的機械和動力系統,汽車電子和軟件系統的重要性日益凸顯。為了確保汽車軟件的質量和可靠性,汽車行業需要一套統一且高效的開發標準。ASPICE(Automotive SPICE)標準應…

通過ESP32芯片模組實現產品智能化升級,啟明云端樂鑫代理商

隨著科技的不斷進步,物聯網(IoT)已經滲透到我們生活的方方面面,成為現代生活不可或缺的一部分。在這場智能化革命中,樂鑫科技以其創新的ESP32芯片模組,為智能家居和智能設備的發展注入了新的活力。作為樂鑫…

msi安裝mysql8 啟動失敗,提示只有在任務處于完成狀態(RanToCompletion、Faulted 或 Canceled)時才能釋放它。

解決方案: 1.打開服務,找到安裝的mysql 2. 右擊,打開屬性,進入【登錄】選項卡,選擇本地系統賬戶。 3. 點擊確定-->應用 4.服務中選擇開始服務 5.服務啟動成功后,在安裝步驟中繼續點擊執行

Post Microsoft Build and AI Day 上海開發者日

點擊藍字 關注我們 編輯:Alan Wang 排版:Rani Sun 這個六一怎么過?來微軟 Reactor,一起過兒童節吧! 6月1日,Microsoft Azure & Microsoft Reactor 面向大小朋友特別推出六一特輯,「Post Mic…

開源進銷存系統

推薦一款開源的進銷存系統 項目地址:進銷存系統 倉庫管理系統 SAAS進銷存 進銷存ERP: 進銷存系統 倉庫管理系統 SAAS進銷存 進銷存ERPhttps://gitee.com/flyemu/jxc.git 主要功能模塊 銷售 采購 庫存 資料 設置 支持saas多租戶,100%開源可二開 …

前端項目上線要準備哪些問題?

上線前 一般開發過程中,會準備好幾條線路,一個是測試環境,一個是正式環境;如果是公司比較大,在此外還會增加一個環境-預上線。 預上線,就是所有的設備,環境,條件和正式線的環境都是一…

iPhone用戶推薦使用的藏漢翻譯小助手:藏漢翻譯通小程序,支持藏文OCR識別文字提取,衛藏語、安多語、康巴語學習背單詞!

網上沖浪時,遇到不會的漢語詞匯,可以復制到藏漢翻譯通小程序中進行翻譯。如果不會拼音,可以使用圖片識別功能掃一掃文字,即可OCR識別提取文字。 此外,藏漢翻譯通小程序現在還支持背單詞和會話速成課程,支持…

C# BurnServiceContractClient 使用方法

目錄 1. 添加服務引用 2. 使用客戶端進行操作 3. 配置文件(App.config) 4. 異步調用 總結 要在C#中使用BurnServiceContractClient,首先需要了解該客戶端的使用場景和目標服務契約。假設BurnServiceContractClient是一個WCF(W…

混元助手 mysql建表語句轉換oracle

提示語 mysql建表語句轉換成oracle,并且有common SQL語句的生成: create ....

Pytorch-Reduction Ops

文章目錄 前言1.torch.argmax()2.torch.argmin()3.torch.amax()4.torch.amin()5.torch.all()6.torch.any()7.torch.max()8.torch.dist()9.torch.logsumexp()10.torch.mean()11.torch.norm()12.torch.nansum()13.torch.prod()14.torch.cumsum()15.torch.cumprod() 前言 1.torch.…

node環境問題(無法加載文件D:\Software\Node.js\node_global\vue.ps1,因為在此系統上禁止運行腳本。)

問題:npm安裝lerna顯示安裝成功,但是lerna -v的時候報錯 解決步驟: 1、輸入:Get-ExecutionPolicy 2、輸入:Set-ExecutionPolicy -Scope CurrentUser(有選項的選Y) 3、輸入:RemoteSi…

【記錄】打印|無需排版,生成證件照打印PDF,打印在任意尺寸的紙上(簡單無損!)

以前我打印證件照的時候,我總是在網上找在線證件照轉換或者別的什么。但是我今天突然就琢磨了一下,用 PDF 打印應該也可以直接打印出來,然后就琢磨出來了,這么一條路大家可以參考一下。我覺得比在線轉換成一張 a4 紙要方便的多&am…

Python爬蟲要掌握哪些東西

學習Python爬蟲,你需要掌握以下幾個關鍵方面的知識: 文章目錄 Python基礎:首先,確保你對Python語言有良好的理解,包括基本語法、數據結構(如列表、字典、集合等)、函數、類和對象、模塊和包的使用等。# 有一個數字列表,要創建新的列表,元素是原列表中每個元素的平方 …

深入探索MySQL SELECT查詢:從基礎到高級,解鎖數據寶藏的密鑰

系列文章目錄 更新ing... MySQL操作全攻略:庫、表、數據、事務全面指南深入探索MySQL SELECT查詢:從基礎到高級,解鎖數據寶藏的密鑰MySQL SELECT查詢實戰:練習題精選,提升你的數據庫查詢技能PyMySQL:連接P…

解決 x-content-sha256 no match 錯誤,對 S3CrtAsyncHttpClient 修改

一、CRT修改核心邏輯: 找到 software.amazon.awssdk.services.s3.internal.crt 包下 S3CrtAsyncHttpClient 按照邏輯需要對 GET請求進行適配 signingConfig.setSignedBodyValue(AwsSigningConfig.AwsSignedBodyValue.EMPTY_SHA256); if("GET".equals(asyncRequ…

orin部署tensorrt、cuda、cudnn、pytorch、onnx

絕大部分參考https://blog.csdn.net/qq_41336087/article/details/129661850 非orin可以參考https://blog.csdn.net/JineD/article/details/131201121 報錯顯卡驅動安裝535沒法安裝、原始是和l4t-cuda的部分文件沖突 Options marked [*] produce a lot of output - pipe it t…

數據結構(一)順序表

目錄 一、概念(一)數據結構的三元素1. 邏輯結構(1)線性結構(2)非線性結構 2. 存儲結構(1)順序存儲(2)鏈式存儲(3)索引存儲 3. 運算 &a…