1. 程式人生 > >2.原子變量 CAS算法

2.原子變量 CAS算法

失敗 cin con @override over ted cbo 沖突 nbsp

前面提到,使用volatile無法保證 變量狀態的原子性操作,所謂原子性,就是不可再分

  如:i++的原子性問題,i++ 的操作實際上分為三個步驟 "讀-改-寫"

  (1)保存i的值(一個臨時變量中)

  (2)遞增i

  (3)返回已保存的值

當在並發的條件下執行 i++,

線程1執行 i++,先從主存中 獲取 i 的 值(假設初值i=0),還未等 執行i = i + 1,此時線程2進來,也從主存中獲取 i 的 值(0)

然後 線程1 執行了 i = i + 1;(i=1) 線程2再執行 i = i + 1(i=1),這種結果是錯誤的

即使使用 volatile ,保證內存的可見性,也是不管用的,即使在主存中進行修改操作,一樣會產生這種錯誤

此時,可以采用 CAS算法 ,CAS算法 是 樂觀鎖的一種(沖突檢測)(hibernate 的樂觀鎖是 加一個 version 字段,來判斷是否發生了並發)

CAS(Compare-And-Swap) 算法 保證數據變量的原子性

CAS 算法是硬件對於並發操作的支持

CAS 包含了三個操作數:

  * ①內存值 V

  * ②預估值 A

  * ③更新值 B

* 當且僅當 V == A 時, V = B; 否則,不會執行任何操作。


過程分析:同樣在 並發條件下 執行 i++

  1、線程1 執行 i++,先從主存中獲取 i 的值(V=i=0) (設i=0),此時線程2進來,也從主存中 獲取 i 的 值(0)

  2、然後線程1 執行 getAndIncrement,即比較和替換一起執行,(過程:再從內存中讀取一遍i的值(A=i=0),讓 A(0) 與 V(0)進行比較,

發現 V==A,此時,B = i+1,將B的值更新到內存中(V = B) )

  3、然後 線程2 開始執行 getAndIncrement,即比較和替換一起執行,過程 和 上述類似,不過再從內存讀一次值,i的值已經變成了 1 ,即A的值也為1

讓A(1)與V(0)進行比較比較,發現 V!=A, 不執行任何操作

註:將 V 與 A 比較的意義在於 判斷 要更新的值(V)是否發生了改變,如果沒有發生改變,則進行 V 的 更新,否則不做任何操作

再發現 V!=A 後,與 synchronize 不一樣的 是,這裏不會發生阻塞,不會等當前線程執行完後,再由CPU 分配時間去給線程2去執行,

而是不停的 循環發送請求,緊接著再去嘗試,再去更新,這也是 CAS算法 比普通同步鎖的做法 效率要高的原因

采用CAS算法之後,當有多個線程訪問 內存中的共享資源,一次只會有一個線程成功,其他線程都會失敗

java.util.concurrent.atomic 包下提供了一些原子操作的常用類:裏面頻繁的使用到了CAS算法來保證變量狀態的原子性操作

  ? AtomicBoolean AtomicInteger AtomicLong AtomicReference

  ? AtomicIntegerArray AtomicLongArray

  ? AtomicMarkableReference

  ? AtomicReferenceArray

  ? AtomicStampedReference

l核心方法:boolean compareAndSet(expectedValue, updateValue) (也是CAS裏面的核心,即比較和替換一起執行)

 1 /*
 2  * 一、i++ 的原子性問題:i++ 的操作實際上分為三個步驟“讀-改-寫”
 3  *           int i = 10;
 4  *           i = i++; //10
 5  * 
 6  *           (1)保存i的值(一個臨時變量中)
 7           (2)遞增i
 8           (3)返回已保存的值
 9  * 
10  * 二、原子變量:在 java.util.concurrent.atomic 包下提供了一些原子變量。
11  *         1. volatile 保證內存可見性
12  *         2. CAS(Compare-And-Swap) 算法保證數據變量的原子性
13  *             CAS 算法是硬件對於並發操作的支持
14  *             CAS 包含了三個操作數:
15  *             ①內存值  V
16  *             ②預估值  A
17  *             ③更新值  B
18  *             當且僅當 V == A 時, V = B; 否則,不會執行任何操作。
19  */
20 
21 public class TestAtomic {
22     public static void main(String[] args) {
23         
24         AtomicDemo ad = new AtomicDemo();
25         for(int i = 0;i<10;i++) {
26             new Thread(ad).start();
27         }
28     }
29 }
30 
31 class AtomicDemo implements Runnable {
32     //創建原子變量
33     private AtomicInteger i = new AtomicInteger(0);
34     @Override
35     public void run() {
36         try {
37             Thread.sleep(200);
38         } catch (InterruptedException e) {
39 
40         }
41         //查看源碼可以發現 循環一直調用compareAndSet(ExceptionValue,UpdateValue)方法,即比較和替換一起執行,
42         //並且如果失敗了,會不停的去嘗試更新(裏面使用到CAS算法的)
43         System.out.println(i.getAndIncrement());
44     }
45     
46     
47 }

2.原子變量 CAS算法