1. 程式人生 > >Java併發程式設計之CAS演算法

Java併發程式設計之CAS演算法

在多執行緒環境下,我們要實現對一個變數自增的話,往往會使用java.util.concurrent.atomic包下的相關實現類。 如下:

public class TestAtomic {
    public static void main(String[] args) {
        ThreadDemo td=new ThreadDemo();
        //開啟二十個執行緒完成自加操作
        for(int x=1;x<=20;x++){
            new Thread(td).start();
        }
    }
}


class
ThreadDemo implements Runnable {
//定義一個AtomicInteger的初始值為0的變數atoInt private AtomicInteger atoInt=new AtomicInteger(0); @Override public void run() { try { //休眠一下,提高併發性 Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getNum()); } public
int getNum() { //每次返回的為當前值的下一個值 return atoInt.incrementAndGet(); } }

這裡用到原子併發包裝類
1:對於變數,原子性操作都用到了volatile關鍵字,確保執行緒之間的可見性。
2:用到了CAS(Compare and Swap)演算法

CAS演算法
這裡用到的主要有三個值
主存值 V :從主存中取出值
預估值 A :對於非原子性的操作,再進行下一次計算操作之前,會再次讀取主存中的值
更新值 B :根據具體的邏輯,有待跟新的值
這裡有關主存的問題,可以參考

這篇文章,在CAS演算法中,如果 V==A 則把B的值複製給V,否則什麼也不做,並進行下一次嘗試。

     *  比如 對於
     *  int num=0;
     *  i=num++;這個操作
     *  在進行num++這個操作的時候,先從主存中獲取num的值,然後再進++操作
     *  很明顯這是兩個步驟,在獲取num的值之後,另一個執行緒可能已經更改了num的值,這時候加的時候明顯有問題
     *  CAS演算法如下:
     *  獲取主存值 V=0
     *  執行之後,在檢視一個主存的值 此時如果還是 A=0(沒有執行緒修改)
     *  根據num++的操作,此時B應該更新到值為0+1=1
     *  V=0
     *  A=0
     *  B=1
     *  因為V==A 此時把B的值重新整理到主存中V=1;
     *  ************************************************
     *  如果在一個執行緒讀取之後,另一個執行緒修改了值,即A=1
     *  V=0          
     *  A=1         
     *  B=1         
     *  V!=A,則不會把B的值重新整理到主存中
     */