首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 並發編程:volatile 關鍵字原理與正確使用場景

     編輯:Java 相關知識

volatile 核心語義

volatile 是 Java 提供的**輕量級同步機制**,保證兩大特性:

  1. 可見性:一線程寫入 volatile 變量,其他線程立即可見最新值
  2. 有序性:禁止指令重排序(內存屏障),保證前後操作順序

不保證原子性:volatile int i; i++; 仍非線程安全!

底層實現原理

編譯器在 volatile 讀寫操作插入內存屏障:

  • 寫屏障:寫入前插入 StoreStore 屏障,寫入後插入 StoreLoad 屏障 → 強制刷新到主存
  • 讀屏障:讀取前插入 LoadLoad 屏障,讀取後插入 LoadStore 屏障 → 強制從主存讀取

效果等同於(但比 synchronized 輕量):

// 寫入
public synchronized void setValue(int value) { this.value = value; }

// 讀取
public synchronized int getValue() { return value; }

正確使用的三個必要條件

同時滿足以下條件才能安全使用 volatile:

  1. 寫入不依賴當前值,或只有單線程寫入
    // 正確:單線程寫入,多線程讀
    volatile boolean shutdownRequested;
    void shutdown() { shutdownRequested = true; } // 單線程調用
    void work() { while (!shutdownRequested) { ... } } // 多線程讀
    
  2. 不參與不變式約束:不與其他狀態變量組成邏輯約束
    // 錯誤:lower <= upper 不變式涉及兩個變量
    volatile int lower, upper;
    void setBounds(int l, int u) { lower = l; upper = u; } // 競態條件!
    
  3. 訪問無需加鎖:純讀寫場景

經典適用場景

場景一:狀態標誌位

public class TaskRunner {
    private volatile boolean cancelled = false;
    
    public void cancel() { cancelled = true; }
    
    public void run() {
        while (!cancelled) { // 立即可見取消信號
            doWork();
        }
    }
}

場景二:雙重檢查鎖定(DCL)單例


public class Singleton {
    private static volatile Singleton instance; // 關鍵!
    
    public static Singleton getInstance() {
        if (instance == null) { // 第一次檢查(無鎖)
            synchronized (Singleton.class) {
                if (instance == null) { // 第二次檢查(有鎖)
                    instance = new Singleton(); // 非原子:分配內存 -> 初始化 -> 賦值
                }
            }
        }
        return instance;
    }
}

volatile 禁止指令重排,防止其他線程看到「半初始化」對象。

場景三:獨立觀察值發布


public class SensorReader {
    private volatile double latestTemperature; // 單寫多讀
    
    public void update(double temp) { latestTemperature = temp; }
    public double getLatest() { return latestTemperature; }
}

常見誤區與反模式

誤區代碼問題修正
volatile int count; count++;複合操作非原子AtomicInteger 或 synchronized
volatile int a, b; a = 1; b = 2;多變量無原子性打包成對象或加鎖
volatile List list; list.add(x);引用可見 ≠ 內容可見用 Collections.synchronizedList 或 CopyOnWriteArrayList
以為 volatile 替代 synchronized語義不同,場景不同理解 JMM,按需選擇

volatile vs synchronized 對比

維度volatilesynchronized
原子性不保證保證
可見性保證保證
有序性保證保證
阻塞不阻塞可能阻塞
適用粒度單變量代碼塊/方法
效能較高(無鎖)較低(上下文切換)

總結

volatile 是「共享變量可見性」的專用工具,**不是萬能鑰匙**。正確使用前提:單寫入者、無不變式依賴、純狀態標誌。複雜協同場景請使用 synchronized、Lock 或並發工具類。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved