1、原子性
對於成員變量a來說,如果線程A執行以下操作:
a++;
此時需要分三步執行:
(1)讀取a的值
(2)將a的值加1
(3)將加1后的值賦給a
在執行以上三步過程中,如果另一個線程B對a進行了操作,那么就不能保證原子性了。
要保證原子性,可以加鎖,如synchronized
2、可見性
要理解可見性,需要先理解cpu的高速緩存。高速緩存是cpu的一塊兒緩存區。如果線程修改了某個變量的值,那么是先將修改過的值先放入緩存區,然后滿足一定條件后才會同步到內存區。同步到內存區后,其他線程才可以看見變量的改變。
可見性是指,當有一個線程修改某個成員變量的值時,其他變量可以立馬看到修改過的值。
比如:
int i=0,j=10;
i=j;
如果線程A執行了以上代碼,這時如果還未將i等於10的結果由高速緩存區同步到內存區,那么B線程讀取到的i的值就是0。
要保證可見性,需要用volatile關鍵字,原理是,線程B會將高速緩存區的結果刷新到內存,它再去讀取內存。這樣讀取的i的值就是10。
3、有序性
int i=10;//語句1
int j=10;//語句2
在執行時,有可能對代碼進行重排序,比如先執行語句2,再執行語句1。但是如果代碼,編程下邊這樣:
int i=0;
int j=0;
j++;//語句3
i=j+1;//語句4
這時,語句3和語句4並不會進行重排序。因為語句3和4之間有依賴關系,重排序后會影響結果。
但是以上說的是單線程的情況。下面看多線程的情況,如下代碼:
boolean flag=false;
private Context context;
//線程1
context=loadContext();//語句1
flag=true;//語句2
//線程2
if(flag){
dowork(context);
}
如果線程1執行的時候,語句1和語句2進行了重排序,先執行語句2,在還沒有執行語句1時,這時線程2 將要執行if,那么就會進入到if語句塊中,而context還是null,所以會出錯。
可以用volatile關鍵字,禁止被它修飾的變量發生指令重排操作。是通過內存屏障去完成的禁止指令重排序。