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

簡單了解JavaCAS的相關(guān)知識原理

 更新時間:2019年11月27日 08:32:15   作者:賜我白日夢  
這篇文章主要介紹了簡單了解JavaCAS的相關(guān)知識,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

JMM與問題引入

為啥先說JMM,因為CAS的實現(xiàn)類中維護的變量都被volatile修飾, 這個volatile 是遵循JMM規(guī)范(不是百分百遵循,下文會說)實現(xiàn)的保證多線程并發(fā)訪問某個變量實現(xiàn)線程安全的手段

一連串的知識點慢慢縷

首先說什么是JMM, JMM就是大家所說的java的內(nèi)存模型, 它是人們在邏輯上做出的劃分, 或者可以將JMM當(dāng)成是一種規(guī)范, 有哪些規(guī)范呢? 如下

  • 可見性: 某一個線程對內(nèi)存中的變量做出改動后,要求其他的線程在第一事件內(nèi)馬上馬得到通知,在CAS的實現(xiàn)中, 可見性其實是通過不斷的while循環(huán)讀取而得到的通知, 而不是被動的得到通知
  • 原子性: 線程在執(zhí)行某個操作的時,要么一起成功,要么就一起失敗
  • 有序性: 為了提高性能, 編譯器處理器會進行指令的重排序, 源碼-> 編譯器優(yōu)化重排 -> 處理器優(yōu)化重排 -> 內(nèi)存系統(tǒng)重排 -> 最終執(zhí)行的命令

JVM運行的實體是線程, 每一個線程在創(chuàng)建之后JVM都會為其創(chuàng)建一個工作空間, 這個工作空間是每一個線程之間的私有空間, 并且任何兩條線程之間的都不能直接訪問到對方的工作空間, 線程之間的通信,必須通過共享空間來中轉(zhuǎn)完成

JMM規(guī)定所有的變量全部存在主內(nèi)存中,主內(nèi)存是一塊共享空間,那么如果某個線程相對主內(nèi)存中共享變量做出修改怎么辦呢? 像

下面這樣:

  • 將共享變量的副本拷貝到工作空間中
  • 對變量進行賦值修改
  • 將工作空間中的變量寫回到內(nèi)存中

JMM還規(guī)定如下:

  • 任何線程在解鎖前必須將工作空間的共享變量立即刷新進內(nèi)存中
  • 線程在加鎖前必須讀取主內(nèi)存中的值更新到自己的工作空間中
  • 加鎖和解鎖是同一把鎖

問題引入

這時候如果多個線程并發(fā)按照上面的三步走去訪問主內(nèi)存中的共享變量的話就會出現(xiàn)線程安全性的問題, 比如說 現(xiàn)在主內(nèi)存中的共享變量是c=1, 有AB兩個線程去并發(fā)訪問這個c變量, 都想進行c++, 現(xiàn)在A將c拷貝到自己的工作空間進行c++, 于是c=2 , 于此同時線程B也進行c++, c在B的工作空間中=2, AB線程將結(jié)果寫回工作空間最終的結(jié)果就是2, 而不是我們預(yù)期的3

相信怎么解決大家都知道, 就是使用JUC,中的原子類就能規(guī)避這個問題

而原子類的底層實現(xiàn)使用的就是CAS技術(shù)

什么是CAS

CAS(compare and swap) 顧名思義: 比較和交換,在JUC中原子類的底層使用的都是CAS無鎖實現(xiàn)線程安全,是一門很炫的技術(shù)

如下面兩行代碼, 先比較再交換, 即: 如果從主內(nèi)存中讀取到的值為4就將它更新為2019

  AtomicInteger atomicInteger = new AtomicInteger(4);
  atomicInteger.compareAndSet(4,2019);

跟進AtomicInteger的源碼如下, 底層維護著一個int 類型的 變量, (當(dāng)然是因為我選擇的原來類是AtomicInteger類型), 并且這個int類型的值被 volatile 修飾

 private volatile int value;

 /**
  * Creates a new AtomicInteger with the given initial value.
  *
  * @param initialValue the initial value
  */
 public AtomicInteger(int initialValue) {
  value = initialValue;
 }

什么是volatile

volatile是JVM提供的輕量的同步機制, 為什么是輕量界別呢? , 剛才在上面說了JMM規(guī)范中提到了三條特性, 而JVM提供的volatile僅僅滿足上面的規(guī)范中的 2/3, 如下:

  • 保證可見性
  • 不保證原子性
  • 禁止指令重排序

單獨的volatile是不能滿足原子性的,即如下代碼在多線程并發(fā)訪問的情況下依然會出現(xiàn)線程安全性問題

private volatile int value;
 
public void add(){
 value++; 
}

那么JUC的原子類是如何實現(xiàn)的 可以滿足原子性呢? 于是就不得不說本片博文的主角, CAS

CAS源碼跟進

我們跟進AtomicInteger中的先遞增再獲取的方法 incrementAndGet()

 public final int incrementAndGet() {
  return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
 }

通過代碼我們看到調(diào)用了Unsafe類來實現(xiàn)

什么是Unsafe類?

進入Unsafe類,可以看到他里面存在大量的 native方法,這些native方法全部是空方法,

這個unsafe類其實相當(dāng)于一個后門,他是java去訪問調(diào)用系統(tǒng)上 C C++ 函數(shù)類庫的方法 如下圖

繼續(xù)跟進這個方法incrementAndGet() 于是我們就來到了我們的主角方法, 關(guān)于這個方法倒是不難理解,主要是搞清楚方法中的var12345到底代表什么就行, 如下代碼+注釋

var1: 上一個方法傳遞進來的: this,即當(dāng)前對象
var2: 上一個方法傳遞進來的valueOffset, 就是內(nèi)存地址偏移量
  通過這個內(nèi)存地址偏移量我能精確的找到要操作的變量在內(nèi)存中的地址
  
var4: 上一個方法傳遞進來的1, 就是每次增長的值
var5: 通過this和內(nèi)存地址偏移量讀取出來的當(dāng)前內(nèi)存中的目標(biāo)值
public final int getAndAddInt(Object var1, long var2, int var4) {
  int var5;
  do {
   var5 = this.getIntVolatile(var1, var2);
  } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

  return var5;
 }

注意它用的是while循環(huán), 相對if(flag){} 這種寫法會多一次判斷, 整體的思路就是 在進行修改之前先進行一次比較,如果讀取到的當(dāng)前值和預(yù)期值是相同的,就自增,否則的話就繼續(xù)輪詢修改

小總結(jié)

通過上面的過程, 其實就能總結(jié)出CAS的底層實現(xiàn)原理

  • volatile
  • 自旋鎖
  • unsafe類

補充: CAS通過Native方法的底層實現(xiàn),本質(zhì)上是操作系統(tǒng)層面上的CPU的并發(fā)原語,JVM會直接實現(xiàn)出匯編層面的指令,依賴于硬件去實現(xiàn), 此外, 對于CPU的原語來說, 有兩條特性1,必定連續(xù), 2.不被中斷

CAS的優(yōu)缺點

優(yōu)點:

它的底層我們看到了通過do-while 實現(xiàn)的自旋鎖來實現(xiàn), 就省去了在多個線程之間進行切換所帶來的額外的上下文切換的開銷

缺點:

  • 通過while循環(huán)不斷的嘗試獲取, 省去了上下文切換的開銷,但是占用cpu的資源
  • CAS只能保證一個共享變量的原子性, 如果存在多個共享變量的話不得不加鎖實現(xiàn)
  • 存在ABA問題

ABA問題

什么是ABA問題

我們這樣玩, 還是AB兩個線程, 給AtomicInteger賦初始值0

A線程中的代碼如下:

  Thread.sleep(3000);
  atomicInteger.compareAndSet(0,2019);

B線程中的代碼如下:

  atomicInteger.compareAndSet(0,1);
  atomicInteger.compareAndSet(1,0);

AB線程同時啟動, 雖然最終的結(jié)果A線程能成果的將值修改成2019,,但是它不能感知到在他睡眠過程中B線程對數(shù)據(jù)進行過改變, 換句話說就是A線程被B線程欺騙了

ABA問題的解決--- AtomicStampedRefernce.java

帶時間戳的原子引用, 實現(xiàn)的機制就是通過 原子引用+版本號來完成, 每次對指定值的修改相應(yīng)的版本號會加1, 實例如下

  // 0表示初始化, 1表示初始版本號
  AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(0, 1);
  reference.getStamp(); // 獲取版本號
  reference.attemptStamp(1,2); // 期待是1, 如果是1就更新為2

原子引用

JUC中我們可以找到像AtomicInteger這樣已經(jīng)定義好了實現(xiàn)類, 但是JUC沒有給我們提供類似這樣 AtomicUser或者 AtomicProduct 這樣自定義類型的原子引用類型啊, 不過java仍然是提供了后門就是 原子引用類型

使用實例:

  User user = getUserById(1);
  AtomicReference<User> userAtomicReference = new AtomicReference<User>();
  user.setUsername("張三");
  userAtomicReference.compareAndSet(user,user);

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

相關(guān)文章

  • Java學(xué)習(xí)隨記之多線程編程

    Java學(xué)習(xí)隨記之多線程編程

    這篇文章主要介紹了Java中的多線程編程的相關(guān)知識,文中的示例代碼介紹詳細,對我們的學(xué)習(xí)或工作有一定的價值,感興趣的小伙伴可以了解一下
    2021-12-12
  • 深入理解Java顯式鎖的相關(guān)知識

    深入理解Java顯式鎖的相關(guān)知識

    今天帶大家學(xué)習(xí)的是關(guān)于Java的相關(guān)知識,文章圍繞著Java顯式鎖展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • java實現(xiàn)掃雷游戲控制臺版

    java實現(xiàn)掃雷游戲控制臺版

    這篇文章主要為大家詳細介紹了java實現(xiàn)掃雷游戲控制臺版,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • Java多線程中的wait、notify和park、unpark的使用詳解

    Java多線程中的wait、notify和park、unpark的使用詳解

    這篇文章主要介紹了Java多線程中的wait、notify和park、unpark的使用詳解,它們都是線程之間進行協(xié)作的手段,都屬于 Object 對象的方法,必須獲得此對象的鎖,才能調(diào)用這幾個方法,需要的朋友可以參考下
    2023-12-12
  • java 文件目錄讀寫刪除操作詳細實現(xiàn)代碼

    java 文件目錄讀寫刪除操作詳細實現(xiàn)代碼

    這篇文章主要介紹了java 文件讀寫刪操作詳細實現(xiàn)代碼,需要的朋友可以參考下
    2017-09-09
  • 詳解Java8中CompletableFuture類的使用

    詳解Java8中CompletableFuture類的使用

    Java?8中引入了CompletableFuture類,它是一種方便的異步編程工具,可以處理各種異步操作,本文將詳細介紹CompletableFuture的使用方式,希望對大家有所幫助
    2023-04-04
  • Spring事務(wù)注解@Transactional失效的八種場景分析

    Spring事務(wù)注解@Transactional失效的八種場景分析

    最近在開發(fā)采用Spring框架的項目中,使用了@Transactional注解,但發(fā)現(xiàn)事務(wù)注解失效了,所以這篇文章主要給大家介紹了關(guān)于Spring事務(wù)注解@Transactional失效的八種場景,需要的朋友可以參考下
    2021-05-05
  • 深入淺出的學(xué)習(xí)Java ThreadLocal

    深入淺出的學(xué)習(xí)Java ThreadLocal

    本文會基于實際場景介紹ThreadLocal如何使用以及內(nèi)部實現(xiàn)機制。 具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • SpringBoot實現(xiàn)整合微信支付方法詳解

    SpringBoot實現(xiàn)整合微信支付方法詳解

    這篇文章主要介紹了SpringBoot實現(xiàn)整合微信支付的過程詳解,文中的示例代碼對我們的工作或?qū)W習(xí)有一定的幫助,感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下
    2021-12-12
  • SpringBoot中獲取微信用戶信息的方法

    SpringBoot中獲取微信用戶信息的方法

    這篇文章主要介紹了SpringBoot中獲取微信用戶信息的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09

最新評論

浪卡子县| 赣州市| 夹江县| 宝清县| 高碑店市| 布尔津县| 龙里县| 鹤岗市| 嘉兴市| 黔南| 中西区| 隆化县| 堆龙德庆县| 和田县| 鄂托克前旗| 资中县| 邹平县| 雷波县| 岳普湖县| 涟源市| 个旧市| 家居| 莱西市| 三门县| 沂南县| 萍乡市| 长岛县| 库尔勒市| 天气| 双流县| 宿松县| 丹东市| 南开区| 措美县| 中山市| 宁化县| 辽源市| 游戏| 阳西县| 杨浦区| 噶尔县|