Java線程(十):CAS__java基礎

來源:互聯網
上載者:User
在Java並發包中有這樣一個包,java.util.concurrent.atomic,該包是對Java部分資料類型的原子封裝,在原有資料類型的基礎上,提供了原子性的操作方法,保證了安全執行緒。下面以AtomicInteger為例,來看一下是如何?的。 [java] view plain copy print ? public final int incrementAndGet() {       for (;;) {           int current = get();           int next = current + 1;           if (compareAndSet(current, next))               return next;       }   }   [java] view plain copy print ? public final int decrementAndGet() {       for (;;) {           int current = get();           int next = current - 1;           if (compareAndSet(current, next))               return next;       }   }  

       以這兩個方法為例,incrementAndGet方法相當於原子性的++i,decrementAndGet方法相當於原子性的--i(根據第一章和第二章我們知道++i或--i不是一個原子性的操作),這兩個方法中都沒有使用阻塞式的方式來保證原子性(如Synchronized),那它們是如何保證原子性的呢,下面引出CAS。 Compare And Swap

       CAS 指的是現代 CPU 廣泛支援的一種對記憶體中的共用資料進行操作的一種特殊指令。這個指令會對記憶體中的共用資料做原子的讀寫操作。簡單介紹一下這個指令的操作過程:首先,CPU 會將記憶體中將要被更改的資料與期望的值做比較。然後,當這兩個值相等時,CPU 才會將記憶體中的數值替換為新的值。否則便不做操作。最後,CPU 會將舊的數值返回。這一系列的操作是原子的。它們雖然看似複雜,但卻是 Java 5 並發機制優於原有鎖機制的根本。簡單來說,CAS 的含義是“我認為原有的值應該是什麼,如果是,則將原有的值更新為新值,否則不做修改,並告訴我原來的值是多少”。(這段描述引自《Java並發編程實踐》)
       簡單的來說,CAS有3個運算元,記憶體值V,舊的預期值A,要修改的新值B。若且唯若預期值A和記憶體值V相同時,將記憶體值V修改為B,否則返回V。這是一種樂觀鎖的思路,它相信在它修改之前,沒有其它線程去修改它;而Synchronized是一種悲觀鎖,它認為在它修改之前,一定會有其它線程去修改它,悲觀鎖效率很低。下面來看一下AtomicInteger是如何利用CAS實現原子性操作的。 volatile變數 [java] view plain copy print ? private volatile int value;          首先聲明了一個volatile變數value,在 第二章我們知道volatile保證了變數的記憶體可見度,也就是所有背景工作執行緒中同一時刻都可以得到一致的值。 [java] view plain copy print ? public final int get() {       return value;   }   Compare And Set [java] view plain copy print ? // setup to use Unsafe.compareAndSwapInt for updates   private static final Unsafe unsafe = Unsafe.getUnsafe();   private static final long valueOffset;// 注意是靜態      static {     try {       valueOffset = unsafe.objectFieldOffset           (AtomicInteger.class.getDeclaredField("value"));// 反射出value屬性,擷取其在記憶體中的位置     } catch (Exception ex) { throw new Error(ex); }   }      public final boolean compareAndSet(int expect, int update) {     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);   }          比較並設定,這裡利用Unsafe類的JNI方法實現,使用CAS指令,可以保證讀-改-寫是一個原子操作。compareAndSwapInt有4個參數,this - 當前AtomicInteger對象,Offset - value屬性在記憶體中的位置(需要強調的是不是value值在記憶體中的位置),expect - 預期值,update - 新值,根據上面的CAS操作過程,當記憶體中的value值等於expect值時,則將記憶體中的value值更新為update值,並返回true,否則返回false。在這裡我們有必要對Unsafe有一個簡單點的認識,從名字上來看,不安全,確實,這個類是用於執行低層級的、不安全操作的方法集合,這個類中的方法大部分是對記憶體的直接操作,所以不安全,但當我們使用反射、並發包時,都間接的用到了Unsafe。 迴圈設定        現在在來看開篇提到的兩個方法,我們拿incrementAndGet來分析一下其實現過程。 [java] view plain copy print ? public final int incrementAndGet() {       for (;;) {// 這樣優於while(true)           int current = get();// 擷取當前值           int next = current + 1;// 設定更新值           if (compareAndSet(current, next))               return next;       }   }          迴圈內,擷取當前值並設定更新值,調用compareAndSet進行CAS操作,如果成功就返回更新至,否則重試到成功為止。這裡可能存在一個隱患,那就是迴圈時間過長,總是在當前線程compareAndSet時,有另一個線程設定了value(點子太被了),這個當然是屬於小機率時間,目前Java貌似還不能處理這種情況。 缺點        雖然使用CAS可以實現非阻塞式的原子性操作,但是會產生ABA問題,關於ABA問題,計劃單拿出一章來整理。        (完) 原文地址: http://blog.csdn.net/ghsau/article/details/38471987

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.