從JAVA看C#中volatile和synchronized關鍵字的作用


最近一直在想C#中 volatile關鍵字到底是用來干什么的?查了很多.NET的文章都是說用volatile修飾的變量可以讓多線程同時修改,這是什么鬼。。。 然后查到了下面這篇JAVA中關於volatile和synchronized關鍵字的概述,總算對volatile和synchronized關鍵字有了個大概的了解,而C#中應該類似,注意C#中沒有synchronized關鍵字,但是有MethodImplAttribute 類 和 SynchronizationAttribute 類與JAVA中的synchronized關鍵字對應。

 

恐怕比較一下volatile和synchronized的不同是最容易解釋清楚的。volatile是變 量修飾符,而synchronized則作用於一段代碼或方法;看如下三句get代碼:

  1. int i1;              int geti1() {return i1;}
  2. volatile int i2;  int geti2() {return i2;}
  3. int i3;              synchronized int geti3() {return i3;}

  geti1()得到存儲在當前線程中i1的數值。多個線程有多個i1變量拷貝,而且這些i1之間可以互不相同。換句話說,另一個線程可能已經改 變了它線程內的i1值,而這個值可以和當前線程中的i1值不相同。事實上,Java有個思想叫“主”內存區域,這里存放了變量目前的“准確值”。每個線程 可以有它自己的變量拷貝,而這個變量拷貝值可以和“主”內存區域里存放的不同。因此實際上存在一種可能:“主”內存區域里的i1值是1,線程1里的i1值 是2,線程2里的i1值是3——這在線程1和線程2都改變了它們各自的i1值,而且這個改變還沒來得及傳遞給“主”內存區域或其他線程時就會發生。   

  而geti2()得到的是“主”內存區域的i2數值。用volatile修飾后的變量不允許有不同於“主”內存區域的變量拷貝。換句話說,一個變量經 volatile修飾后在所有線程中必須是同步的;任何線程中改變了它的值,所有其他線程立即獲取到了相同的值。理所當然的,volatile修飾的變量 存取時比一般變量消耗的資源要多一點,因為線程有它自己的變量拷貝更為高效。   

  既然volatile關鍵字已經實現了線程間數據同步,又要synchronized干什么呢?呵呵,它們之間有兩點不同。首 先,synchronized獲得並釋放監視器——如果兩個線程使用了同一個對象鎖,監視器能強制保證代碼塊同時只被一個線程所執行——這是眾所周知的事 實。但是,synchronized也同步內存:事實上,synchronized在“主”內存區域同步整個線程的內存。

因此,執行geti3()方法做 了如下幾步:

1. 線程請求獲得監視this對象的對象鎖(假設未被鎖,否則線程等待直到鎖釋放)

2. 線程內存的數據被消除,從“主”內存區域中讀入(Java虛擬機能優化此步。。。[后面的不知道怎么表達,汗]) ,也就是說在synchronized聲明的代碼塊中跨線程訪問變量,訪問到的都是變量的最新值

3. 代碼塊被執行

4. 對於變量的任何改變現在可以實時且安全地寫到“主”內存區域中(不過geti3()方法不會改變變量值) ,也就是說在synchronized聲明的代碼塊中跨線程對變量做任何修改,都會實時且安全地寫到“主”內存區域中

5. 線程釋放監視this對象的對象鎖   

 

因此volatile只是在線程內存和“主”內存間同步某個變量的值,而synchronized通過鎖定和解鎖某個監視器同步代碼塊中的所有變量值。顯然 synchronized要比volatile消耗更多資源。


免責聲明!

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



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