談談對volatile關鍵字的理解

1. volatile的特性

volatile是Java語言提供的一種輕量級的同步機制,用來確保將變數得更新操作通知到其它執行緒。具備三種特性:

  • 保證變數的可見性
  • 對於volatile修飾的變數進行單次讀/寫操作可以保證原子性,對於i++這樣的多次操作不保證原子性
  • 防止指令重排(通過在指令序列中插入記憶體屏障來禁止特定類型的處理器重排序)。

2. volatile關鍵字和synchronized關鍵字的區別

區別可以從以下四點闡述:

  • volatile關鍵字是執行緒同步的輕量級實現,其性能比synchronized關鍵字好。但是volatile關鍵字只能修飾變數而synchronized關鍵字可以修飾方法以及程式碼塊。synchronized關鍵字在JDK1.6之前是一種重量級鎖,在1.6之後進行了一系列的優化(主要是為了減少獲得鎖和釋放鎖帶來的性能消耗而引入偏向鎖和輕量級鎖使得效率有所提升),實際中使用synchronized的場景相對較多;
  • 多執行緒情況下訪問volatile關鍵字修飾的變數不會造成阻塞,而synchronized關鍵字可能會造成阻塞;
  • volatile可以保證變數的可見性,但不能完全保證數據操作的原子性,而synchronized技能保證變數可見性也能保證原子性;
  • volatile關鍵字主要用於解決變數在多個執行緒之間的可見性問題,而synchronized關鍵字解決的是多個執行緒之間訪問資源的同步性。

3. 使用volatile關鍵字的場景

單例模式(雙檢鎖DCL)

public class Singleton {
    
    private volatile static singleton;
    
    private Singleton() {
    }
    
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

使用volatile關鍵字修飾singleton,防止指令重排。如果不加volatile關鍵字,則會出如下問題:在執行if (singleton == null)判斷時,有可能singleton對象正在初始化的過程中還未完成,因此會通過雙重檢查,然後又進行以此singleton對象的初始化,從而導致出現多個實例。