欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java原子操作CAS原理解析

 更新時間:2019年10月25日 10:08:46   作者:ねぇ  
這篇文章主要介紹了Java原子操作CAS原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

一、CAS(Compare And Set)

Compare And Set(或Compare And Swap),CAS是解決多線程并行情況下使用鎖造成性能損耗的一種機(jī)制,CAS操作包含三個操作數(shù)——內(nèi)存位置(V)、預(yù)期原值(A)、新值(B)。如果內(nèi)存位置的值與預(yù)期原值相匹配,那么處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論哪種情況,它都會在CAS指令之前返回該位置的值。CAS有效地說明了“我認(rèn)為位置V應(yīng)該包含值A(chǔ);如果包含該值,則將B放到這個位置;否則,不要更改該位置,只告訴我這個位置現(xiàn)在的值即可。

​ 在java中可以通過鎖和循環(huán)CAS的方式來實現(xiàn)原子操作。Java中 java.util.concurrent.atomic包相關(guān)類就是 CAS的實現(xiàn),atomic包里包括以下類:

AtomicBoolean 可以用原子方式更新的 boolean 值。
AtomicInteger 可以用原子方式更新的 int 值。
AtomicIntegerArray 可以用原子方式更新其元素的 int 數(shù)組。
AtomicIntegerFieldUpdater 基于反射的實用工具,可以對指定類的指定 volatile int 字段進(jìn)行原子更新。
AtomicLong 可以用原子方式更新的 long 值。
AtomicLongArray 可以用原子方式更新其元素的 long 數(shù)組。
AtomicLongFieldUpdater 基于反射的實用工具,可以對指定類的指定 volatile long 字段進(jìn)行原子更新。
AtomicMarkableReference AtomicMarkableReference 維護(hù)帶有標(biāo)記位的對象引用,可以原子方式對其進(jìn)行更新。
AtomicReference 可以用原子方式更新的對象引用。
AtomicReferenceArray 可以用原子方式更新其元素的對象引用數(shù)組。
AtomicReferenceFieldUpdater<T,V> 基于反射的實用工具,可以對指定類的指定 volatile 字段進(jìn)行原子更新。
AtomicStampedReference AtomicStampedReference 維護(hù)帶有整數(shù)“標(biāo)志”的對象引用,可以用原子方式對其進(jìn)行更新。

二、AtomicInteger

AtomicInteger可以用原子方式更新的 int 值。AtomicInteger 可用在應(yīng)用程序中(如以原子方式增加的計數(shù)器),并且不能用于替換 Integer。但是,此類確實擴(kuò)展了 Number,允許那些處理基于數(shù)字類的工具和實用工具進(jìn)行統(tǒng)一訪問。 我們拿 AtomicInteger為例來學(xué)習(xí)下 CAS操作是如何實現(xiàn)的。

通常情況下,在 Java中,i++等類似操作并不是線程安全的,因為 i++可分為三個獨(dú)立的操作:獲取變量當(dāng)前值,為該值+1,然后寫回新的值。在沒有額外資源可以利用的情況下,只能使用加鎖才能保證讀-改-寫這三個操作時“原子性”的。但是利用加鎖的方式來實現(xiàn)該功能的話,代碼將非常復(fù)雜及難以維護(hù),如:

synchronized (lock) { 
  i++; 
} 

相關(guān)類中還需要增加 Object lock等額外標(biāo)志,這樣就帶來了很多麻煩,增加了很多業(yè)務(wù)無關(guān)代碼,給開發(fā)與維護(hù)帶來了不便。
​ 然而利用 atomic包中相關(guān)類型就可以很簡單實現(xiàn)此操作,以下是一個計數(shù)程序?qū)嵗?/p>

public class Counter {
  private AtomicInteger ai = new AtomicInteger();
  private int i = 0;
 
  public static void main(String[] args) { 
    final Counter cas = new Counter(); 
    List<Thread> threads = new ArrayList<Thread>();
    // 添加100個線程 
    for (int j = 0; j < 100; j++) { 
      threads.add(new Thread(new Runnable() {
        public void run() { 
          // 執(zhí)行100次計算,預(yù)期結(jié)果應(yīng)該是10000 
          for (int i = 0; i < 100; i++) { 
            cas.count(); 
            cas.safeCount(); 
          } 
        } 
      })); 
    } 
    //開始執(zhí)行 
    for (Thread t : threads) {
      t.start(); 
    } 
    // 等待所有線程執(zhí)行完成 
    for (Thread t : threads) {
      try { 
        t.join(); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      } 
    } 
    System.out.println("非線程安全計數(shù)結(jié)果:"+cas.i); 
    System.out.println("線程安全計數(shù)結(jié)果:"+cas.ai.get()); 
  } 
 
  /** 使用CAS實現(xiàn)線程安全計數(shù)器 */ 
  private void safeCount() { 
    for (;;) { 
      int i = ai.get(); 
      // 如果當(dāng)前值 == 預(yù)期值,則以原子方式將該值設(shè)置為給定的更新值 
      boolean suc = ai.compareAndSet(i, ++i); 
      if (suc) { 
        break; 
      } 
    } 
  } 
  /** 非線程安全計數(shù)器 */ 
  private void count() { 
    i++; 
  } 
} 
/**
非線程安全計數(shù)結(jié)果:9942
線程安全計數(shù)結(jié)果:10000
*/

其中非線程安全計數(shù)器所計算的結(jié)果每次都不相同且不正確,而線程安全計數(shù)器計算的結(jié)果每次都是正確的。

三、存在的問題

CAS雖然很高效的解決原子操作,但是CAS仍然存在三大問題:ABA問題、循環(huán)時間長開銷大、只能保證一個共享變量的原子操作。

ABA問題:因為CAS需要在操作值的時候檢查下值有沒有發(fā)生變化,如果沒有發(fā)生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那么使用CAS進(jìn)行檢查時會發(fā)現(xiàn)它的值沒有發(fā)生變化,但是實際上卻變化了。ABA問題的解決思路就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加一,那么A-B-A 就會變成1A-2B-3A。 從Java1.5開始JDK的 atomic包里提供了一個類AtomicStampedReference 來解決ABA問題。這個類的 compareAndSet方法作用是首先檢查當(dāng)前引用是否等于預(yù)期引用,并且當(dāng)前標(biāo)志是否等于預(yù)期標(biāo)志,如果全部相等,則以原子方式將該引用和該標(biāo)志的值設(shè)置為給定的更新值。

循環(huán)時間長開銷大:自旋CAS如果長時間不成功,會給CPU帶來非常大的執(zhí)行開銷。如果JVM能支持處理器提供的pause指令那么效率會有一定的提升,pause指令有兩個作用,第一它可以延遲流水線執(zhí)行指令(de-pipeline),使CPU不會消耗過多的執(zhí)行資源,延遲的時間取決于具體實現(xiàn)的版本,在一些處理器上延遲時間是零。第二它可以避免在退出循環(huán)的時候因內(nèi)存順序沖突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush),從而提高CPU的執(zhí)行效率?!?/p>

只能保證一個共享變量的原子操作:當(dāng)對一個共享變量執(zhí)行操作時,我們可以使用循環(huán)CAS的方式來保證原子操作,但是對多個共享變量操作時,循環(huán)CAS就無法保證操作的原子性,這個時候就可以用鎖,或者有一個取巧的辦法,就是把多個共享變量合并成一個共享變量來操作。比如有兩個共享變量i=2,j=a,合并一下ij=2a,然后用CAS來操作ij。從Java1.5開始JDK提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個變量放在一個對象里來進(jìn)行CAS操作。

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

您可能感興趣的文章:

相關(guān)文章

  • SpringBoot實現(xiàn)微信及QQ綁定登錄的示例代碼

    SpringBoot實現(xiàn)微信及QQ綁定登錄的示例代碼

    本文主要介紹了SpringBoot實現(xiàn)微信及QQ綁定登錄的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Eclipse最新版使用過程中遇到的問題總結(jié)

    Eclipse最新版使用過程中遇到的問題總結(jié)

    這篇文章主要介紹了Eclipse最新版使用過程中遇到的問題總結(jié)的相關(guān)資料,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • SpringBoot+SpringCloud用戶信息微服務(wù)傳遞實現(xiàn)解析

    SpringBoot+SpringCloud用戶信息微服務(wù)傳遞實現(xiàn)解析

    這篇文章主要介紹了SpringBoot+SpringCloud實現(xiàn)登錄用戶信息在微服務(wù)之間的傳遞,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Java中雙重檢查鎖(double checked locking)的正確實現(xiàn)

    Java中雙重檢查鎖(double checked locking)的正確實現(xiàn)

    雙重檢查鎖(Double-Check Locking),顧名思義,通過兩次檢查,并基于加鎖機(jī)制,實現(xiàn)某個功能,下面這篇文章主要給大家介紹了關(guān)于Java中雙重檢查鎖(double checked locking)的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • 實戰(zhàn)分布式醫(yī)療掛號系統(tǒng)登錄接口整合阿里云短信詳情

    實戰(zhàn)分布式醫(yī)療掛號系統(tǒng)登錄接口整合阿里云短信詳情

    這篇文章主要為大家介紹了實戰(zhàn)分布式醫(yī)療掛號系統(tǒng)登錄接口整合阿里云短信詳情,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>
    2022-04-04
  • java 分行讀取實例

    java 分行讀取實例

    今天小編就為大家分享一篇java 分行讀取實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Android入門簡單實例

    Android入門簡單實例

    這篇文章主要介紹了Android入門簡單實例,對于初學(xué)Android的朋友有一定的借鑒價值,需要的朋友可以參考下
    2014-08-08
  • Springboot項目實現(xiàn)將類從@ComponentScan中排除

    Springboot項目實現(xiàn)將類從@ComponentScan中排除

    這篇文章主要介紹了Springboot項目實現(xiàn)將類從@ComponentScan中排除,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 一文快速掌握Spring?Cloud?Stream

    一文快速掌握Spring?Cloud?Stream

    這篇文章主要介紹了Spring?Cloud?Stream詳解,本篇文章所涉及到的demo練習(xí)使用的cloud?2021.0.3+?springboot2.6.8,通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • 輕松掌握J(rèn)ava代理模式

    輕松掌握J(rèn)ava代理模式

    這篇文章主要幫助大家輕松掌握J(rèn)ava代理模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09

最新評論