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

Java 關鍵字 volatile 與 synchronized 深度對比:作用機制與核心區別

     編輯:Java 相關知識

代碼直觀對比


// 普通變量
int i1;
int getI1() { return i1; }

// volatile 變量
volatile int i2;
int getI2() { return i2; }

// synchronized 方法
int i3;
synchronized int getI3() { return i3; } // 語法錯誤,僅示意,實際應用於方法/代碼塊

核心機制差異

1. 普通變量(i1) - 線程本地緩存

JMM 模型:主內存 + 線程工作內存(寄存器、L1/L2 Cache)。

  • 線程讀寫變量時,先從主內存拷貝副本到工作內存
  • 操作副本,寫回時機不確定(由 JVM/CPU 優化決定)
  • 後果:線程 A 修改 i1=2,線程 B 可能仍讀到舊值 1(可見性問題)

2. volatile 變量(i2) - 強制主內存同步

  • 讀取:直接從主內存讀取,忽略工作內存副本
  • 寫入:直接寫入主內存,並**立即刷新**到其他線程工作內存(緩存一致性協議 MESI)
  • 禁止指令重排序:內存屏障保證 happens-before 語義
  • 適用場景:狀態標誌、單次初始化、獨立變量更新

3. synchronized - 監視器鎖機制

  • 互斥訪問:同一時刻僅一線程持有鎖,進入同步塊/方法
  • 內存語義:獲取鎖時**清空工作內存、從主內存重讀**;釋放鎖時**將工作內存刷回主內存**
  • 鎖對象:`synchronized(this)` 鎖實例,`synchronized(Class)` 鎖類對象
  • 重入性:同一線程可重複獲取同一鎖
  • 適用場景:複合操作(檢查-執行)、多變量關聯更新、臨界區保護

詳細對比表

維度volatilesynchronized
作用對象變量代碼塊/方法
核心保證可見性 + 有序性原子性 + 可見性 + 有序性
互斥性無有(互斥鎖)
阻塞線程不阻塞會阻塞/等待
性能開銷較低(內存屏障)較高(上下文切換、監視器操作)
適用粒度單個變量多變量/復雜邏輯
死鎖風險無有(不當嵌套鎖)
JVM 優化禁止重排序鎖粗化、鎖消除、偏向鎖等

典型應用場景對比

volatile 經典:雙重檢查鎖單例(JDK 5+)

public class Singleton {
    private volatile static Singleton instance; // 關鍵:禁止指令重排序
    
    public static Singleton getInstance() {
        if (instance == null) {                    // 第一次檢查
            synchronized (Singleton.class) {       // 加鎖
                if (instance == null) {            // 第二次檢查
                    instance = new Singleton();    // 非原子操作:分配內存→初始化→賦值
                }
            }
        }
        return instance;
    }
}

無 `volatile` 時,`instance = new Singleton()` 可能重排序為:分配內存 → 賦值引用 → 初始化對象,導致其他線程看到「非 null 但未初始化完成」的對象。

synchronized 經典:線程安全計數器

public class Counter {
    private int count = 0;
    
    public synchronized void increment() { count++; } // 復合操作:讀-改-寫
    
    public synchronized int getCount() { return count; }
}

`count++` 非原子,必須用 synchronized 或 `AtomicInteger` 保證原子性。

進階:Java 內存模型 (JMM) 三大特性

特性volatilesynchronizedfinal
原子性❌(長整型除外)✅❌
可見性✅✅✅(構造函數結束前)
有序性✅(禁止重排)✅(鎖語義)✅(構造函數內)

最佳實踐建議

  1. 優先使用高級併發工具:`AtomicInteger`、`ConcurrentHashMap`、`CountDownLatch` 等 JUC 組件
  2. volatile 適用:獨立狀態標誌、單次發布、無鎖優化場景
  3. synchronized 適用:復合操作、多變量不變性、臨界區
  4. 避免過早優化:先正確,後優化;JDK 6+ synchronized 優化極大(偏向鎖、輕量級鎖、鎖消除)
  5. 組合使用:volatile 保証發布可見性,synchronized 保証復合操作原子性
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved