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

Java原子操作CAS原理解析

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

一、CAS(Compare And Set)

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

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

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

二、AtomicInteger

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

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

synchronized (lock) { 
  i++; 
} 

相關(guān)類中還需要增加 Object lock等額外標(biāo)志,這樣就帶來了很多麻煩,增加了很多業(yè)務(wù)無關(guān)代碼,給開發(fā)與維護(hù)帶來了不便。
​ 然而利用 atomic包中相關(guān)類型就可以很簡單實(shí)現(xiàn)此操作,以下是一個(gè)計(jì)數(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個(gè)線程 
    for (int j = 0; j < 100; j++) { 
      threads.add(new Thread(new Runnable() {
        public void run() { 
          // 執(zhí)行100次計(jì)算,預(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("非線程安全計(jì)數(shù)結(jié)果:"+cas.i); 
    System.out.println("線程安全計(jì)數(shù)結(jié)果:"+cas.ai.get()); 
  } 
 
  /** 使用CAS實(shí)現(xiàn)線程安全計(jì)數(shù)器 */ 
  private void safeCount() { 
    for (;;) { 
      int i = ai.get(); 
      // 如果當(dāng)前值 == 預(yù)期值,則以原子方式將該值設(shè)置為給定的更新值 
      boolean suc = ai.compareAndSet(i, ++i); 
      if (suc) { 
        break; 
      } 
    } 
  } 
  /** 非線程安全計(jì)數(shù)器 */ 
  private void count() { 
    i++; 
  } 
} 
/**
非線程安全計(jì)數(shù)結(jié)果:9942
線程安全計(jì)數(shù)結(jié)果:10000
*/

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

三、存在的問題

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

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

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

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

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

您可能感興趣的文章:

相關(guān)文章

  • Maven項(xiàng)目如何查找jar包是由哪個(gè)依賴引入的

    Maven項(xiàng)目如何查找jar包是由哪個(gè)依賴引入的

    這篇文章主要介紹了Maven項(xiàng)目如何查找jar包是由哪個(gè)依賴引入的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java?Stream流語法示例詳解

    Java?Stream流語法示例詳解

    這篇文章主要為大家詳細(xì)介紹了Java的Stream流,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • Java中equals方法使用及重寫練習(xí)

    Java中equals方法使用及重寫練習(xí)

    equals是在object類中的方法,在object中equals是用來看看兩個(gè)參數(shù)是否引用的是同一個(gè)對(duì)象,下面這篇文章主要給大家介紹了關(guān)于Java中equals方法使用及重寫練習(xí)的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • 使用@Builder導(dǎo)致無法創(chuàng)建無參構(gòu)造方法的解決

    使用@Builder導(dǎo)致無法創(chuàng)建無參構(gòu)造方法的解決

    這篇文章主要介紹了使用@Builder導(dǎo)致無法創(chuàng)建無參構(gòu)造方法的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 解決SpringMVC 返回Java8 時(shí)間JSON數(shù)據(jù)的格式化問題處理

    解決SpringMVC 返回Java8 時(shí)間JSON數(shù)據(jù)的格式化問題處理

    本篇文章主要介紹了解決SpringMVC 返回Java8 時(shí)間JSON數(shù)據(jù)的格式化問題處理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • Java實(shí)現(xiàn)讀取和寫入properties文件

    Java實(shí)現(xiàn)讀取和寫入properties文件

    這篇文章主要介紹了Java實(shí)現(xiàn)讀取和寫入properties文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 解決SpringBoot啟動(dòng)報(bào)錯(cuò):Failed?to?load?property?source?from?location?'classpath:/application.yml'問題

    解決SpringBoot啟動(dòng)報(bào)錯(cuò):Failed?to?load?property?source?from?l

    這篇文章主要介紹了解決SpringBoot啟動(dòng)報(bào)錯(cuò):Failed?to?load?property?source?from?location?'classpath:/application.yml'問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • 使用FeignClient設(shè)置動(dòng)態(tài)Url

    使用FeignClient設(shè)置動(dòng)態(tài)Url

    這篇文章主要介紹了使用FeignClient設(shè)置動(dòng)態(tài)Url方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • SpringBoot整合Thymeleaf的方法

    SpringBoot整合Thymeleaf的方法

    這篇文章主要介紹了SpringBoot整合Thymeleaf的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java實(shí)現(xiàn)json字符串格式化處理的工具類

    java實(shí)現(xiàn)json字符串格式化處理的工具類

    這篇文章主要為大家詳細(xì)介紹了如何使用java實(shí)現(xiàn)json字符串格式化處理的工具類,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01

最新評(píng)論

华安县| 平遥县| 全州县| 志丹县| 施甸县| 临江市| 达日县| 综艺| 曲松县| 平原县| 黔西| 双峰县| 乐安县| SHOW| 沐川县| 宁明县| 揭西县| 全南县| 休宁县| 湖南省| 永德县| 荥经县| 安岳县| 河津市| 张家港市| 惠东县| 临泉县| 兴国县| 漠河县| 鹤岗市| 印江| 洛隆县| 全椒县| 司法| 新乐市| 桃园市| 深州市| 广饶县| 新巴尔虎左旗| 香格里拉县| 东城区|