揮發物
將 volatile
關鍵字新增到欄位會向編譯器指示欄位的值可能會被多個單獨的執行緒更改。volatile
關鍵字的主要目的是防止僅採用單執行緒訪問的編譯器優化。使用 volatile
可確保欄位的值是可用的最新值,並且該值不受非易失性值的快取限制。
最好將多個執行緒可能使用的每個變數標記為 volatile
,以防止由於幕後優化而導致的意外行為。請考慮以下程式碼塊:
public class Example
{
public int x;
public void `DoStuff()`
{
x = 5;
// the compiler will optimize this to y = 15
var y = x + 10;
/* the value of x will always be the current value, but y will always be "15" */
Debug.WriteLine("x = " + x + ", y = " + y);
}
}
在上面的程式碼塊中,編譯器讀取語句 x = 5
和 y = x + 10
,並確定 y
的值總是最終為 15.因此,它將優化最後一個語句為 y = 15
。然而,變數 x
實際上是 public
欄位,並且 x
的值可以在執行時通過分別作用於該欄位的不同執行緒來修改。現在考慮這個修改過的程式碼塊。請注意,欄位 x
現在宣告為 volatile
。
public class Example
{
public volatile int x;
public void `DoStuff()`
{
x = 5;
// the compiler no longer optimizes this statement
var y = x + 10;
/* the value of x and y will always be the correct values */
Debug.WriteLine("x = " + x + ", y = " + y);
}
}
現在,編譯器查詢欄位 x
的讀取用法,並確保始終檢索欄位的當前值。這確保即使多個執行緒正在讀取和寫入此欄位,也始終檢索 x
的當前值。
volatile
只能用於 class
es 或 struct
s 中的欄位。下面是不是有效的 :
public void MyMethod()
{
volatile int x;
}
volatile
只能應用於以下型別的欄位:
- 已知為引用型別的引用型別或泛型型別引數
- 原始型別如
sbyte
,byte
,short
,ushort
,int
,uint
,char
,float
和bool
- 基於
byte
,sbyte
,short
,ushort
,int
或uint
的列舉型別 IntPtr
和UIntPtr
備註:
- 該
volatile
修飾符通常用於由多個執行緒而不使用 lock 語句能夠連續訪問訪問的領域。 volatile
關鍵字可以應用於引用型別的欄位volatile
關鍵字不會在 32 位平臺原子上對 64 位基元進行操作。Interlocked.Read
和Interlocked.Exchange
等聯鎖操作仍必須用於這些平臺上的安全多執行緒訪問。