在多線程環境下,我們要實作對一個變量自增的話,往往會使用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