国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Java 并發(fā)編程】CAS 原理解析

這篇具有很好參考價(jià)值的文章主要介紹了【Java 并發(fā)編程】CAS 原理解析。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1. 什么是 CAS?

1.1 悲觀鎖與樂(lè)觀鎖

悲觀鎖的原理是每次實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪改的時(shí)候都進(jìn)?阻塞,防?數(shù)據(jù)發(fā)?臟讀。

樂(lè)觀鎖的原理是在數(shù)據(jù)庫(kù)更新的時(shí)候,??個(gè) version 字段來(lái)記錄版本號(hào),然后通過(guò)?較是不是??要修改的版本號(hào)再進(jìn)?修改。這其中就引出了?種?較交換的思路來(lái)實(shí)現(xiàn)數(shù)據(jù)的?致性,事實(shí)上,CAS 也是基于這樣的原理。

1.2 CAS 是什么?

CAS 是指 Compare And Swap,比較并交換,是一種無(wú)鎖原子算法,在不使用鎖(沒(méi)有線程被阻塞)的情況下實(shí)現(xiàn)多線程之間的變量同步。

JAVA 底層是 C++ 實(shí)現(xiàn),映射到操作系統(tǒng)就是一條 cmpxchg 硬件匯編指令(保證原子性),其作用就是讓 CPU 將內(nèi)存值更新為新值,但是有個(gè)條件,內(nèi)存值必須與期望值相同。并且 CAS 操作無(wú)需用戶態(tài)與內(nèi)核態(tài)切換,直接在用戶態(tài)對(duì)內(nèi)存進(jìn)行讀寫(xiě)操作(意味著不會(huì)阻塞/線程上下文切換)。

java.util.concurrent.atomic 包中的原子類(lèi)就是通過(guò) CAS 來(lái)實(shí)現(xiàn)了樂(lè)觀鎖。

CAS 算法涉及到三個(gè)操作數(shù):

  • 需要更新的內(nèi)存變量值 V(volatile);

  • 上一次從內(nèi)存中讀取,進(jìn)行比較的預(yù)期原值 E(except);

  • 要寫(xiě)入的新值 N(new)。

當(dāng)且僅當(dāng) V 的值等于 E 時(shí),CAS 通過(guò)原子方式用新值 N 來(lái)更新 V 的值(“比較 + 更新” 整體是一個(gè)原子操作),否則不會(huì)執(zhí)行任何操作,這就是一次 CAS 的操作。一般情況下,“更新” 是一個(gè)不斷重試的操作。

【Java 并發(fā)編程】CAS 原理解析
簡(jiǎn)單說(shuō),CAS 需要你額外給出一個(gè)期望值,也就是你認(rèn)為這個(gè)變量現(xiàn)在應(yīng)該是什么樣子的,如果變量不是你想象的那樣,說(shuō)明它已經(jīng)被別人修改過(guò)了,你只需要重新讀取,設(shè)置新期望值,再次嘗試修改就好了。

2. CAS 核心源碼

java.util.concurrent.atomic 包中的原子類(lèi)就是通過(guò) CAS 思想來(lái)實(shí)現(xiàn),CAS 思想實(shí)現(xiàn)靠的是 Unsafe 類(lèi)。以 AtomicInteger 為例:

【Java 并發(fā)編程】CAS 原理解析

Unsafe 類(lèi)是 CAS 的核心類(lèi),由于 Java 方法無(wú)法直接訪問(wèn)底層系統(tǒng),需要通過(guò)本地(native)方法來(lái)訪問(wèn),Unsafe 相當(dāng)于一個(gè)后門(mén),基于該類(lèi)可以直接操作特定內(nèi)存的數(shù)據(jù)。Unsafe 類(lèi)存在于 sun.misc 包中,其內(nèi)部方法操作可以像C的指針一樣直接操作內(nèi)存。

valueOffset 表示當(dāng)前類(lèi)對(duì)象中使用變量的偏移量,Unsafe 就是根據(jù)內(nèi)存偏移地址獲取數(shù)據(jù)的。

value 要修改的值,用 volatile 修飾,保證了多線程之間的內(nèi)存可見(jiàn)性。

一起看一下 AtomicInteger.getAndIncrement() 方法是怎么替換內(nèi)容的:

public final int getAndIncrement() {
	// 拿到當(dāng)前對(duì)象和當(dāng)前對(duì)象的地址,然后加一。
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

// var1 就是當(dāng)前對(duì)象,var2 就是當(dāng)前對(duì)象的內(nèi)存地址,var4 就是要加的數(shù)
public final int getAndAddInt(Object var1, long var2, int var4) {
	// 舊的預(yù)期值
    int var5;
    do {
        // 獲得當(dāng)前 var2 地址中的值,可以理解為從當(dāng)前主物理內(nèi)存中拷貝一份到自己的本地內(nèi)存
        var5 = this.getIntVolatile(var1, var2);
    } 
	// 如果var1 = var5,執(zhí)行var5 + var4,執(zhí)行成功返回 true,跳出 while 循環(huán),執(zhí)行失敗返回false,自旋
	while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *)index_oop_from_field_offset_long(p, offset);

  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
} UNSAFE_END

首先獲取 var5 舊的預(yù)期值,然后調(diào)用底層代碼 Unsafe_CompareAndSetInt。下面看 Unsafe_CompareAndSetInt 怎么做的:

第一步通過(guò) JNIHandles::resolve() 獲取 obj 在內(nèi)存中 OOP 實(shí)例;
第二步根據(jù)成員變量 value 反射后計(jì)算出的內(nèi)存偏移值 offset 去內(nèi)存中取指針 addr;
最后通過(guò) Atomic::cmpxchg(x, addr, e) 實(shí)現(xiàn) CAS。

3. CAS 實(shí)現(xiàn)原子操作的三大問(wèn)題

3.1 ABA 問(wèn)題

并發(fā)環(huán)境下,假設(shè)初始條件是 A,去修改數(shù)據(jù)時(shí),發(fā)現(xiàn)是 A 就會(huì)執(zhí)行修改。但是看到的雖然是 A,中間可能發(fā)生了 A 變 B,B 又變回 A 的情況。此 A 已經(jīng)非彼 A,數(shù)據(jù)即使成功修改,也可能有問(wèn)題。

怎么解決 ABA 問(wèn)題?

加版本號(hào)。

每次修改變量,都在這個(gè)變量的版本號(hào)上加1,這樣發(fā)生 A->B->A 時(shí),雖然 A 的值沒(méi)變,但是它的版本號(hào)已經(jīng)變了,再判斷版本號(hào)就會(huì)發(fā)現(xiàn)此時(shí)的 A 已經(jīng)被改過(guò)了。參考樂(lè)觀鎖的版本號(hào),這種做法可以給數(shù)據(jù)帶上了一種時(shí)效性的檢驗(yàn)。

Java 提供了 AtomicStampReference 類(lèi),它的 compareAndSet 方法首先檢查當(dāng)前的對(duì)象引用值是否等于預(yù)期引用,并且當(dāng)前版本號(hào)(Stamp)標(biāo)志是否等于預(yù)期標(biāo)志,如果全部相等,則以原子方式將引用值和版本號(hào)標(biāo)志的值更新為給定的更新值。

3.2 循環(huán)性能開(kāi)銷(xiāo)

自旋 CAS,如果一直循環(huán)執(zhí)行,一直不成功,會(huì)給 CPU 帶來(lái)非常大的執(zhí)行開(kāi)銷(xiāo)。

怎么解決循環(huán)性能開(kāi)銷(xiāo)問(wèn)題?

在 Java 中,很多使用自旋 CAS 的地方,會(huì)有一個(gè)自旋次數(shù)的限制,超過(guò)一定次數(shù),就停止自旋。

3.3 只能保證一個(gè)變量的原子操作

CAS 保證的是對(duì)一個(gè)變量執(zhí)行操作的原子性,如果對(duì)多個(gè)變量操作時(shí),CAS 目前無(wú)法直接保證操作的原子性的。

怎么解決只能保證一個(gè)變量的原子操作問(wèn)題?

  • 可以考慮改用鎖來(lái)保證操作的原子性
  • 可以考慮合并多個(gè)變量,將多個(gè)變量封裝成一個(gè)對(duì)象,從 Java 1.5 開(kāi)始,JDK 提供了 AtomicReference 類(lèi)來(lái)保證引用對(duì)象之間的原子性,就可以把多個(gè)變量放在一個(gè)對(duì)象里來(lái)進(jìn)行 CAS 操作。

4. synchronized、volatile、CAS 比較

(1)synchronized 是悲觀鎖,屬于搶占式,會(huì)引起其他線程阻塞。

(2)volatile 提供多線程共享變量可見(jiàn)性和禁止指令重排序優(yōu)化。

(3)CAS 是基于沖突檢測(cè)的樂(lè)觀鎖(非阻塞)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-458506.html

到了這里,關(guān)于【Java 并發(fā)編程】CAS 原理解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • (學(xué)習(xí)筆記-進(jìn)程管理)什么是悲觀鎖、樂(lè)觀鎖?

    (學(xué)習(xí)筆記-進(jìn)程管理)什么是悲觀鎖、樂(lè)觀鎖?

    最底層的兩種就是 [互斥鎖和自旋鎖],有很多高級(jí)的鎖都是基于它們實(shí)現(xiàn)的。可以認(rèn)為它們是各種鎖的地基,所以我們必須清楚它們之間的區(qū)別和應(yīng)用。 加鎖的目的就是保證共享資源在任意時(shí)間內(nèi),只有一個(gè)線程訪問(wèn),這樣就可以避免多線程導(dǎo)致共享數(shù)據(jù)錯(cuò)亂的問(wèn)題。 當(dāng)已

    2024年02月11日
    瀏覽(25)
  • 「JUC并發(fā)編程」初識(shí)CAS鎖(概述、底層原理、原子引用、自旋鎖、缺點(diǎn))

    「JUC并發(fā)編程」初識(shí)CAS鎖(概述、底層原理、原子引用、自旋鎖、缺點(diǎn))

    概述 CAS的全稱(chēng)為 Compare-And-Swap ,直譯就是 對(duì)比交換 。是一條 CPU的原子指令 ,其作用是讓CPU 先 進(jìn)行比較兩個(gè)值是否相等, 然后 原子地更新某個(gè)位置的值。經(jīng)過(guò)調(diào)查發(fā)現(xiàn),其實(shí)現(xiàn)方式是 基于硬件平臺(tái)的匯編指令 ,就是說(shuō)CAS是靠硬件實(shí)現(xiàn)的, JVM只是封裝了匯編調(diào) 用,那些

    2024年02月16日
    瀏覽(20)
  • java JUC并發(fā)編程 第六章 CAS

    java JUC并發(fā)編程 第六章 CAS

    第一章 java JUC并發(fā)編程 Future: link 第二章 java JUC并發(fā)編程 多線程鎖: link 第三章 java JUC并發(fā)編程 中斷機(jī)制: link 第四章 java JUC并發(fā)編程 java內(nèi)存模型JMM: link 第五章 java JUC并發(fā)編程 volatile與JMM: link 第六章 java JUC并發(fā)編程 CAS: link 第七章 java JUC并發(fā)編程 原子操作類(lèi)增強(qiáng): link 第八章

    2024年02月10日
    瀏覽(23)
  • Java——并發(fā)編程(CAS、Lock和AQS)

    Java——并發(fā)編程(CAS、Lock和AQS)

    答: Lock 接口比同步方法和同步塊提供了 更具擴(kuò)展性的鎖操作 。他們?cè)试S更靈活的結(jié)構(gòu),可以具有完全不同的性質(zhì),并且可以支持多個(gè)相關(guān)類(lèi)的條件對(duì)象。 可以使鎖更公平; 可以使線程在等待鎖的時(shí)候響應(yīng)中斷; 可以讓線程嘗試獲取鎖,并在無(wú)法獲取鎖的時(shí)候立即返回或

    2024年02月06日
    瀏覽(37)
  • JavaEE 初階篇-深入了解 CAS 機(jī)制與12種鎖的特征(如樂(lè)觀鎖和悲觀鎖、輕量級(jí)鎖與重量級(jí)鎖、自旋鎖與掛起等待鎖、可重入鎖與不可重入鎖等等)

    JavaEE 初階篇-深入了解 CAS 機(jī)制與12種鎖的特征(如樂(lè)觀鎖和悲觀鎖、輕量級(jí)鎖與重量級(jí)鎖、自旋鎖與掛起等待鎖、可重入鎖與不可重入鎖等等)

    ??博客主頁(yè):?【 小扳_-CSDN博客】 ?感謝大家點(diǎn)贊??收藏?評(píng)論? 文章目錄 ? ? ? ? 1.0 樂(lè)觀鎖與悲觀鎖概述 ? ? ? ? 1.1 悲觀鎖(Pessimistic Locking) ? ? ? ? 1.2 樂(lè)觀鎖(Optimistic Locking) ? ? ? ? 1.3 區(qū)別與適用場(chǎng)景 ? ? ? ? 2.0 輕量級(jí)鎖與重量級(jí)鎖概述 ? ? ? ? 2.1 真正加

    2024年04月16日
    瀏覽(40)
  • JUC并發(fā)編程16 | CAS自旋鎖

    JUC并發(fā)編程16 | CAS自旋鎖

    是什么,干什么,解決了什么痛點(diǎn)?如何解決,如何使用。 原子類(lèi):java.util.concurrent.atomic 在沒(méi)有CAS之前,多線程環(huán)境不使用原子類(lèi)保證線程安全i++等操作,會(huì)出現(xiàn)數(shù)據(jù)問(wèn)題,如果直接加鎖synchronized,資源的開(kāi)銷(xiāo)就比較大 在出現(xiàn)CAS之后,多線程環(huán)境,使用原子類(lèi)保證線程安全

    2024年02月04日
    瀏覽(26)
  • JUC并發(fā)編程學(xué)習(xí)筆記(十八)深入理解CAS

    JUC并發(fā)編程學(xué)習(xí)筆記(十八)深入理解CAS

    什么是CAS 為什么要學(xué)CAS:大廠你必須深入研究底層!有所突破! java層面的cas-------compareAndSet compareAndSet(int expectedValue, int newValue) 期望并更新,達(dá)到期望值就更新、否則就不更新! Unsafe類(lèi) java不能直接操作內(nèi)存,但是可以調(diào)用c++,c++可以操作內(nèi)存,java可以通過(guò)native定義

    2024年02月05日
    瀏覽(28)
  • 悲觀鎖&樂(lè)觀鎖

    1.悲觀鎖 悲觀鎖介紹(百科): 悲觀鎖,正如其名,它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來(lái)自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個(gè)數(shù)據(jù)處理過(guò)程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制(也只有數(shù)據(jù)庫(kù)層

    2024年02月08日
    瀏覽(24)
  • django實(shí)現(xiàn)悲觀鎖樂(lè)觀鎖

    前期準(zhǔn)備 1.原生mysql悲觀鎖 2.orm實(shí)現(xiàn)上述(悲觀鎖)? 3 樂(lè)觀鎖秒殺--》庫(kù)存還有,有的人就沒(méi)成功 ?

    2024年02月12日
    瀏覽(26)
  • 悲觀鎖和樂(lè)觀鎖(易懂)

    這里可以把悲觀鎖看作悲觀的人,啥事都往最壞的方向想。樂(lè)觀鎖看作樂(lè)觀的人,啥事都往最好的方向想。 首先,說(shuō)一下悲觀鎖。 悲觀鎖就是假設(shè)并發(fā)情況下一定會(huì)有其他線程來(lái)修改數(shù)據(jù),因此在處理數(shù)據(jù)之前,先將數(shù)據(jù)鎖住,確保其他線程不能進(jìn)行修改 。感覺(jué)像一個(gè)過(guò)于

    2024年02月08日
    瀏覽(23)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包