目錄
什麼是CAS
CAS實作無鎖定程式設計
頭痛的ABA問題
具體應用場景 
JDK中的CAS應用
企業開發中的樂觀鎖應用
首頁 Java java教程 CAS與java樂觀鎖怎麼用

CAS與java樂觀鎖怎麼用

May 01, 2023 pm 08:07 PM
java cas

什麼是CAS

CAS是CompareAndSwap,即比較和交換。為什麼CAS沒有用到鎖還能保證並發情況下安全的操作數據呢,名字其實非常直觀的表明了CAS的原理,具體修改數據過程如下:

  1. 用CAS操作資料時,將資料原始值和要修改的值一併傳遞給方法

  2. 比較目前目標變數值與傳進去的原始值是否相同

  3. #如果相同,表示目標變數沒有被其他執行緒修改,直接修改目標變數值即可

  4. #如果目標變數值與原始值不同,那麼證明目標變數已經被其他線程修改過,本次CAS修改失敗

從上述過程可以看到CAS其實保證的是安全的修改數據,但是修改存在失敗的可能性,即目標變量數據修改不成功,這個時候我們要循環判斷CAS修改資料結果,如果失敗重試。

思維比較縝密的同學可能擔心CAS本身這個比較與替換的操作產生並發安全問題,實際應用中這種情況不會發生,比較與替換由JDK借助硬件級別的CAS原語來保證比較替換是一個原子性動作。

CAS實作無鎖定程式設計

無鎖定程式指的是不使用鎖定的情況下保證安全的操作共享變數在並發程式設計中,我們用各種鎖來保證共享變數的安全性。即在保證一個執行緒未操作完共享變數的時候其他執行緒不能操作同一共享變數。
正確的使用鎖可以保證並發情況下資料安全,但是在並發程度不高,競爭不激烈的時候,取得鎖和釋放鎖就成了沒必要的效能浪費。這種情況下可以考慮利用CAS確保資料安全,實現無鎖定編程 

頭痛的ABA問題

上面我們已經了解了CAS保證安全操作共享變數的原理,但是上述CAS操作還存在缺陷。假設目前執行緒存取的共享變數值為A,在執行緒1存取共享變數過程中,執行緒2操作共享變數將其賦值為B,執行緒2處理完自己的邏輯後又將共享變數賦值為A。這時線程1比較共享變量值A與原始值A相同,誤以為沒有其他線程操作共享變量,直接返回操作成功。這就是ABA問題。雖然大部分業務不需要關心共享變數是否有過其他更改,只要原始值與當前值一致就能得到正確的結果,但是有一些敏感場景不光要考慮共享變數結果上等同於沒有被修改過,同時也不能接受共享變數過程上被其他執行緒修改過。幸運的是ABA問題也有成熟的解決方案,我們為共享變數加上一個版本號,每當共享變數被修改這個版本號值就會自增。在CAS運算中我們比較的不是原始變數值,而是共享變數的版本號碼。每次運算共享變數更新的版本號碼都是唯一的,所以能夠避免ABA問題。

具體應用場景 

JDK中的CAS應用

首先多個執行緒對普通變數進行並發操作是不安全的,一個執行緒的操作結果可能被其他執行緒覆蓋掉,例如現在我們用兩個線程,每個線程將初始值為1的共享變數增加一,如果沒有同步機制的話共享變數結果很可能小於3。即可能線程1和線程2都讀到了初始值1,線程1將其賦值為2,線程2所在內存讀取到的值還是1不會變,線程2也將變量增加1然後賦值成2,這樣最終結果是2小於預期結果3。自增操作不是原子性操作導致了這個共享變數操作不安全問題。為了解決這個問題,JDK提供了一系列原子類提供相應的原子操作。下面是AtomicInteger中的getAndIncrement方法原始碼,讓我們從原始碼來看是怎麼利用CAS實作執行緒安全的原子性的整形變數相加操作。

<code>/**<br> * 原子性的将当前值增加1<br> *<br> * @return 返回自增前的值<br> */<br>public final int getAndIncrement() {<br>    return unsafe.getAndAddInt(this, valueOffset, 1);<br>}<br></code>
登入後複製
 

可以看到getAndIncrement實際呼叫了UnSafe類別的getAndAddInt方法實作原子操作,以下是getAndAddInt原始碼

<code>/**<br> * 原子的将给定值与目标字变量相加并重新赋值给目标变量<br> *<br> * @param o 要更新的变量所在的对象<br> * @param offset 变量字段的内存偏移值<br> * @param delta 要增加的数字值<br> * @return 更改前的原始值<br> * @since 1.8<br> */<br>public final int getAndAddInt(Object o, long offset, int delta) {<br>    int v;<br>    do {<br>    	// 获取当前目标目标变量值<br>        v = getIntVolatile(o, offset);<br>    // 这句代码是关键, 自旋保证相加操作一定成功<br>    // 如果不成功继续运行上一句代码, 获取被其他<br>    // 线程抢先修改的变量值, 在新值基础上尝试相加<br>    // 操作, 保证了相加操作的原子性<br>    } while (!compareAndSwapInt(o, offset, v, v + delta));<br>    return v;<br>}<br></code>
登入後複製

我們都對鎖很熟悉, 例如可重入鎖ReentrantLock, JDK提供的各種鎖基本上都依賴AbstractQueuedSynchronizer這個類別, 當多個線程嘗試獲取鎖時會進入一個隊列等待, 其中多線程入隊操作的原子性就是用CAS來保證的. 原始碼如下:

<code>/**<br> * 锁底层等待获取锁的线程入队操作<br> * @param node 要入队的线程节点<br> * @return 入队节点的前驱节点<br> */<br>private Node enq(final Node node) {<br>// 自旋等待节点入队, 通过cas保证并发情况下node安全正确入队<br>    for (;;) {<br>        Node t = tail;<br>        // head为空时构造dummy node初始化head和tail<br>        if (t == null) {<br>            if (compareAndSetHead(new Node()))<br>                tail = head;<br>        } else {<br>            node.prev = t;<br>            // 如果cas设置tail失败了<br>            // 下个循环取到了最新的其他线程抢先设置的tail<br>            // 继续尝试设置.<br>            if (compareAndSetTail(t, node)) {<br>                t.next = node;<br>                return t;<br>            }<br>        }<br>    }<br>}<br>/**<br> * 原子性的设置tail尾节点为新入队的节点<br> */<br>private final boolean compareAndSetTail(Node expect, Node update) {<br>// 可以看到此处又是调用了Unsafe类下的原子操作方法<br>// 如果目标字段(tail尾节点字段)当前值是预期值<br>// 即没有被其他线程抢先修改成功, 那么就设置成功<br>// 返回true<br>    return unsafe.compareAndSwapObject(this, tailOffset, expect, update);<br>}</code>  
  
登入後複製

企業開發中的樂觀鎖應用

除了JDK中Uusafe類別提供的各種原子性操作外,我們實際開發中可以用CAS思想保證並發情況下安全的操作資料庫。 假設有user表結構以及資料如下,version欄位是實作樂觀鎖的關鍵

##usercoupon_numversion#1朱小明#0 0

假设我们有一个用户领取优惠券的按钮,怎么防止用户快速点击按钮造成重复领取优惠券的情况呢。我们要安全的更改id为1的用户的coupon_num优惠券数量,将version字段作为CAS比较的版本号,即可避免重复增加优惠券数量,比较和替换这个逻辑通过WHERE条件来实现. 涉及sql如下:

<code>UPDATE user <br>SET coupon_num = coupon_num + 1, version = version + 1 <br>WHERE version = 0</code>
登入後複製

可以看到,我们查询出id为1的数据, 版本号为0,修改数据的同时把当前版本号当做条件即可实现安全修改,如果修改失败,证明已经被其他线程修改过,然后看具体业务决定是否需要自旋尝试再次修改。这里要注意考虑竞争激烈的情况下多个线程自旋导致过度的性能消耗,根据并发量选择适合自己业务的方式

#id

以上是CAS與java樂觀鎖怎麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1327
25
PHP教程
1273
29
C# 教程
1253
24
突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP與Python:用例和應用程序 PHP與Python:用例和應用程序 Apr 17, 2025 am 12:23 AM

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。

See all articles