Java併發程式設計之CAS演算法
阿新 • • 發佈:2018-12-31
在多執行緒環境下,我們要實現對一個變數自增的話,往往會使用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的值重新整理到主存中
*/