volatile 關鍵字提供「輕量級同步」:保證可見性(讀取最新值)、防止指令重排、不快取於暫存器,但不具備原子性。專家建議慎用,僅在嚴格條件下適用。
Thread.VolatileRead/Write、Thread.MemoryBarrier 強制快取一致volatile 關鍵字編譯為對應的 Volatile 指令,適用型別:byte, sbyte, short, ushort, int, uint, char, float, bool、參考型別、特定基礎型別的列舉| 特性 | lock | volatile |
|---|---|---|
| 互斥性 | 是 | 否 |
| 可見性 | 是 | 是 |
| 原子性 | 是(配合關鍵區) | 否 |
| 阻塞 | 可能 | 從不 |
| 效能(讀多寫少) | 較低 | 優於 lock |
x = x + 1、x++ 等「讀-改-寫」模式)a + b == c)簡單說:該變數完全獨立於程式狀態,甚至不記得自己當前值。
private volatile bool stopped;
public void Stop() { stopped = true; }
public void FindFiles() {
while (!stopped) {
// 搜尋檔案...
}
}
false → true 後不再改回public class LargeDataObject {
public volatile LargeDataType LargeData; // 參考型別也可 volatile
public void InitInBackground() {
// 大量初始化工作...
LargeData = new LargeDataType(); // 發布完成參考
}
}
public class OtherClass {
public void DoWork() {
while (true) {
if (largeDataObject.LargeData != null) {
Process(largeDataObject.LargeData); // 保證看到完整建構的物件
}
}
}
}
volatile 時,可能看到「參考非 null 但物件尚未完整建構」的狀態(指令重排)LargeDataType 本身是執行緒安全或不可變(發布後不再修改)// 錯誤:volatile 無法保證 ++ 原子性
private volatile int counter;
public void Increment() { counter++; } // 多執行緒下會遺失更新
public class ThreadSafeCounter {
private volatile int value;
public int Value => value; // 讀取:volatile,極快
public int Increase() {
lock (this) { // 寫入:加鎖保證原子
return value++;
}
}
}
lock(this) 公開鎖物件,易造成死結(建議用私有 readonly object _sync = new object())volatile 提供脆弱的同步機制。
僅在變數真正獨立於其他狀態(不依賴當前值、無不變式關聯)時使用。
能用lock、Interlocked、ConcurrentDictionary等高階建構時,優先選擇它們。
除非你完全理解 記憶體模型、指令重排、快取一致性,否則遠離 volatile。