並發編程的三大特性


並發編程的三大特性

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關鍵字,禁止被它修飾的變量發生指令重排操作。是通過內存屏障去完成的禁止指令重排序。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM