天天看點

Java并發程式設計之CAS算法

在多線程環境下,我們要實作對一個變量自增的話,往往會使用java.util.concurrent.atomic包下的相關實作類。 如下:

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


class ThreadDemo implements Runnable {
    //定義一個AtomicInteger的初始值為0的變量atoInt
    private AtomicInteger atoInt=new AtomicInteger();
    @Override
    public void run() {
        try {
            //休眠一下,提高并發性
            Thread.sleep();
        } 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的值重新整理到主存中
     */
           

Java并發之CountDownLatch

繼續閱讀