Java中的volatile關鍵字 - Break易站
Java中的volatile關鍵字
使用volatile是另一種使類執行緒安全的方法(如synchronized,atomic wrapper)。執行緒安全意味著一個方法或類例項可以被多個執行緒同時使用,沒有任何問題。
考慮下面的簡單例子。
class SharedObj { //在一個執行緒中對sharedVar所做的更改 //可能不會立即反映在其他執行緒中 static int sharedVar = 6; }
假設兩個執行緒在SharedObj上工作。如果兩個執行緒在不同的處理器上執行,則每個執行緒都可以擁有自己的sharedVariable本地副本。如果一個執行緒修改了它的值,這個改變可能不會立即反映到主存中的原始記憶體中。這取決於快取的寫入策略。現在另一個執行緒不知道導致資料不一致的修改值。
下圖顯示如果兩個執行緒在不同的處理器上執行,那麼sharedVariable的值在不同的執行緒中可能會有所不同。
請注意,在沒有任何同步操作的情況下寫入普通變數可能對任何讀取執行緒都不可見(此行為稱為順序一致性)。儘管大多數現代硬體提供了良好的快取一致性,因此很可能一個快取中的更改反映在其他快取中,但依靠硬體來“修復”錯誤的應用程式並不是一個好習慣。
class SharedObj { //volatile 關鍵字在這裡確保在一個執行緒中進行的更改是 立即反映在其他執行緒中 static volatile int sharedVar = 6; }
請注意,volatile不應與靜態修飾符混淆。靜態變數是在所有物件之間共享的類成員。主記憶體中只有一個副本。
volatile和synchronized:
在我們繼續之前,讓我們看看鎖和同步的兩個重要特性。
- 互斥:這意味著一次只有一個執行緒或程序可以執行一段程式碼(臨界區)。
- 可見性:這意味著一個執行緒對共享資料所做的更改對其他執行緒可見。
Java的同步關鍵字保證了互斥和可見性。如果我們使修改共享變數值的執行緒塊同步化,則只有一個執行緒可以進入該塊,並且由它所做的更改將反映在主記憶體中。所有其他嘗試同時進入該塊的執行緒都將被阻塞並進入睡眠狀態。
在某些情況下,我們可能只需要可見性而不是原子性。在這種情況下使用同步是矯枉過正的,並可能導致可伸縮性問題。這裡不穩定來救援。易變變數具有同步的可見性特徵,但不具有原子性特徵。volatile變數的值永遠不會被快取,所有的寫入和讀取操作都將在主存中進行。然而,揮發性物質的使用僅限於非常有限的一組情況,因為大多數時間是需要原子數的。例如一個簡單的增量語句,如x = x + 1; 或者x ++似乎是一個單獨的操作,但它確實是一個複雜的讀 - 修改 - 寫操作序列,必須以原子方式執行。