最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Compare And Swap底層原理及代碼示例詳解

 更新時間:2020年10月31日 15:23:14   作者:柒  
這篇文章主要介紹了Compare And Swap底層原理及代碼示例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

概念

CAS的全稱是Compare-And-Swap,它是cpu并發(fā)原語

它的功能是判斷內(nèi)存某個位置的值是否為預(yù)期值。如果是則更改為新的值,這個過程是原子的

CAS并發(fā)原語體現(xiàn)在java語言中就是sun.misc.Unsafe類的各個方法。調(diào)用UnSafe類中的CAS方法,JVM會幫我們實現(xiàn)出CAS匯編指令,這是一種完全依賴于硬件的功能,通過它實現(xiàn)了原子操作,再次強調(diào),由于CAS是一種系統(tǒng)原語,原語屬于操作系統(tǒng)用于范疇,是由若干條指令組成,用于完成某個功能的一個過程,并且原語的執(zhí)行必須是連續(xù)的,在執(zhí)行過程中不允許被中斷,也就是說CAS是一條CPU的原子指令,不會造成所謂的數(shù)據(jù)不一致的問題,也就是說CAS是線程安全的。

代碼使用

首先使用AtomicInteger創(chuàng)建了一個實例,并初始化為5

// 創(chuàng)建一個原子類

AtomicInteger atomicInteger= new AtomicInteger(5)

然后調(diào)用CAS方法,企圖更新成2019,這里有兩個參數(shù),一個是5,表示期望值,第二個就是我們要更新的值

atomicInteger.compareAndSet(5,2019)

然后再次使用了一個方法,同樣將值改為1024

atomicInteger.compareAndSet(5,1024)

完整代碼如下:

public class CASDemo {
  public static void main(String[] args) {
    // 創(chuàng)建一個原子類
    AtomicInteger atomicInteger = new AtomicInteger(5);

    /**
     * 一個是期望值,一個是更新值,但期望值和原來的值相同時,才能夠更改
     * 假設(shè)三秒前,我拿的是5,也就是expect為5,然后我需要更新成 2019
     */
    System.out.println(atomicInteger.compareAndSet(5, 2019) + "\t current data: " + atomicInteger.get());

    System.out.println(atomicInteger.compareAndSet(5, 1024) + "\t current data: " + atomicInteger.get());
  }
}

上面代碼的執(zhí)行結(jié)果為:


這是因為我們執(zhí)行第一個的時候,期望值和原本值是滿足的,因此修改成功,但是第二次后,主內(nèi)存的值已經(jīng)改成了2019,不滿足期望值,因此返回了false,本次寫入失敗


這個就類似于SVN或者Git的版本號,如果沒有人更改過,就能夠正常提交,否者需要先將代碼pull下來,合并代碼后,然后提交

CAS底層原理

首先我們先看看atomicInteger.getAndIncrement()方法的源碼


從這里能夠看到,底層又調(diào)用了一個unsafe類的getAndAddInt方法

unsafe類


Unsafe是CAS的核心類,由于Java方法無法直接訪問底層系統(tǒng),需要通過本地(Native)方法來訪問,Unsafe相當于一個后門,基于該類可以直接操作特定的內(nèi)存數(shù)據(jù),Unsafe類存在sun.misc包中,其內(nèi)部方法操作可以像C指針一樣直接操作內(nèi)存,因為Java中的CAS操作的執(zhí)行依賴于Unsafe類的方法。

注意Unsafe類的所有方法都是native修飾的,也就是說unsafe類中的方法都直接調(diào)用操作系統(tǒng)底層資源執(zhí)行相應(yīng)的任務(wù)

為什么Atomic修飾的包裝類,能夠保證原子性,依靠的就是底層的unsafe類

變量valueOffset

表示該變量值在內(nèi)存中的偏移地址,因為Unsafe就是根據(jù)內(nèi)存偏移地址獲取數(shù)據(jù)的


從這里我們可以看到,通過valueOffset,直接通過內(nèi)存地址,獲取到值,然后進行加1操作

變量value用volatile修飾

保證了多線程之間的內(nèi)存可見性


var5:就是我們從主內(nèi)存中拷貝到工作內(nèi)存中的值

那么操作的時候,需要比較工作內(nèi)存中的值,和主內(nèi)存中的值進行比較

假設(shè)執(zhí)行 compareAndSwapInt返回false,那么就一直執(zhí)行 while方法,直到期望的值和真實值一樣

  • val1:AtomicInteger對象本身
  • var2:該對象值得引用地址
  • var4:需要變動的數(shù)量
  • var5:用var1和var2找到的內(nèi)存中的真實值
    • 用該對象當前的值與var5比較
    • 如果相同,更新var5 + var4 并返回true
    • 如果不同,繼續(xù)取值然后再比較,直到更新完成

這里沒有用synchronized,而用CAS,這樣提高了并發(fā)性,也能夠?qū)崿F(xiàn)一致性,是因為每個線程進來后,進入的do while循環(huán),然后不斷的獲取內(nèi)存中的值,判斷是否為最新,然后在進行更新操作。

假設(shè)線程A和線程B同時執(zhí)行g(shù)etAndInt操作(分別跑在不同的CPU上)

  • tomicInteger里面的value原始值為3,即主內(nèi)存中AtomicInteger的 value 為3,根據(jù)JMM模型,線程A和線程B各自持有一份價值為3的副本,分別存儲在各自的工作內(nèi)存
  • 線程A通過getIntVolatile(var1 , var2) 拿到value值3,這是線程A被掛起(該線程失去CPU執(zhí)行權(quán))
  • 線程B也通過getIntVolatile(var1, var2)方法獲取到value值也是3,此時剛好線程B沒有被掛起,并執(zhí)行了compareAndSwapInt方法,比較內(nèi)存的值也是3,成功修改內(nèi)存值為4,線程B打完收工,一切OK
  • 這是線程A恢復,執(zhí)行CAS方法,比較發(fā)現(xiàn)自己手里的數(shù)字3和主內(nèi)存中的數(shù)字4不一致,說明該值已經(jīng)被其它線程搶先一步修改過了,那么A線程本次修改失敗,只能夠重新讀取后在來一遍了,也就是在執(zhí)行do while
  • 線程A重新獲取value值,因為變量value被volatile修飾,所以其它線程對它的修改,線程A總能夠看到,線程A繼續(xù)執(zhí)行compareAndSwapInt進行比較替換,直到成功。

Unsafe類 + CAS思想: 也就是自旋,自我旋轉(zhuǎn)底層匯編

Unsafe類中的compareAndSwapInt是一個本地方法,該方法的實現(xiàn)位于unsafe.cpp中

  • 先想辦法拿到變量value在內(nèi)存中的地址
  • 通過Atomic::cmpxchg實現(xiàn)比較替換,其中參數(shù)X是即將更新的值,參數(shù)e是原內(nèi)存的值

CAS不加鎖,保證一次性,但是需要多次比較

  • 循環(huán)時間長,開銷大(因為執(zhí)行的是do while,如果比較不成功一直在循環(huán),最差的情況,就是某個線程一直取到的值和預(yù)期值都不一樣,這樣就會無限循環(huán))
  • 只能保證一個共享變量的原子操作
    • 當對一個共享變量執(zhí)行操作時,我們可以通過循環(huán)CAS的方式來保證原子操作
    • 但是對于多個共享變量操作時,循環(huán)CAS就無法保證操作的原子性,這個時候只能用鎖來保證原子性
  • 引出來ABA問題?

總結(jié)CAS

CAS是compareAndSwap,比較當前工作內(nèi)存中的值和主物理內(nèi)存中的值,如果相同則執(zhí)行規(guī)定操作,否者繼續(xù)比較直到主內(nèi)存和工作內(nèi)存的值一致為止

CAS應(yīng)用

CAS有3個操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的更新值B。當且僅當預(yù)期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否者什么都不做

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用maven項目pom.xml文件配置打包功能和靜態(tài)資源文件自帶版本號功能

    使用maven項目pom.xml文件配置打包功能和靜態(tài)資源文件自帶版本號功能

    在Maven項目中,通過pom.xml文件配置打包功能,可以控制構(gòu)建過程,生成可部署的包,同時,為了緩存控制與版本更新,可以在打包時給靜態(tài)資源文件如JS、CSS添加版本號,這通常通過插件如maven-resources-plugin實現(xiàn)
    2024-09-09
  • Java十分鐘精通集合的使用與原理下篇

    Java十分鐘精通集合的使用與原理下篇

    這章就對上一章的集合進行代碼操作,去學習如果創(chuàng)建集合,以及對集合數(shù)據(jù)的處理,下面跟小編一起來看看吧
    2022-03-03
  • Java Json字符串的雙引號(

    Java Json字符串的雙引號("")括號如何去掉

    這篇文章主要介紹了Java Json字符串的雙引號("")括號如何去掉?具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java常用集合與映射的線程安全問題小結(jié)

    Java常用集合與映射的線程安全問題小結(jié)

    本文給大家介紹Java常用集合與映射的線程安全問題小結(jié),本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2025-04-04
  • JAVA寶藏工具hutool的使用

    JAVA寶藏工具hutool的使用

    開發(fā)過程中總是會遇到需要自己自定義工具類的情況,做一些數(shù)據(jù)轉(zhuǎn)換、字符串操作、日期處理、加解密、編解碼、金額計算等,本文就詳細的介紹有一個工具類hutool的使用,感興趣的可以了解一下
    2021-10-10
  • Java concurrency之AtomicLongArray原子類_動力節(jié)點Java學院整理

    Java concurrency之AtomicLongArray原子類_動力節(jié)點Java學院整理

    這篇文章主要介紹了Java concurrency之AtomicLongArray原子類的相關(guān)知識,感興趣的朋友參考下吧
    2017-06-06
  • Java?九宮重排(滿分解法)

    Java?九宮重排(滿分解法)

    本文主要介紹了Java?九宮重排(滿分解法),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • SpringBoot之多環(huán)境打包與配置文件排除方式

    SpringBoot之多環(huán)境打包與配置文件排除方式

    這篇文章主要介紹了SpringBoot之多環(huán)境打包與配置文件排除方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java中String類常用方法使用詳解

    Java中String類常用方法使用詳解

    String類是一個很常用的類,它位于java.lang包下,是Java語言的核心類,用來保存代碼中的字符串常量的,并且封裝了很多操作字符串的方法。本文就來聊聊String類常用方法使用,感興趣的可以了解一下
    2022-08-08
  • 詳解Java引用類型的參數(shù)也是值傳遞

    詳解Java引用類型的參數(shù)也是值傳遞

    這篇文章主要介紹了Java引用類型的參數(shù)也是值傳遞,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03

最新評論

宁南县| 资兴市| 汪清县| 和静县| 靖西县| 安多县| 长岛县| 吴忠市| 梁平县| 丹东市| 茂名市| 汶上县| 桦川县| 定远县| 和田县| 许昌县| 拜城县| 修武县| 韩城市| 深州市| 烟台市| 汤阴县| 来凤县| 扎囊县| 沙洋县| 兴山县| 武宣县| 湖北省| 合江县| 二连浩特市| 丰都县| 高陵县| 台北市| 广南县| 原阳县| 武义县| 鹰潭市| 唐海县| 通海县| 额尔古纳市| 五大连池市|