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

Java 線程安全深度解析:JMM 內存模型、內置鎖、CAS 無鎖機制與 Atomic 原子類原理

     編輯:Java 綜合教學

線程安全的本質:JMM 與可見性問題

JVM 中存在主內存,每個線程有私有的工作內存。線程操作變量時:

  1. 從主內存複製副本到工作內存
  2. 在工作內存中運算
  3. 寫回主內存

多線程同時操作同一變量,若無同步機制,會導致臟讀、丟失更新、指令重排等不可預知結果。線程安全的目標:保證原子性、可見性、有序性。

方案一:內置鎖

同步代碼塊 vs 同步方法

// 同步代碼塊(推薦,粒度細)
synchronized(lockObject) {
    // 臨界區
}

// 同步方法(鎖住整個對象 this)
public synchronized void method() { ... }

// 靜態同步方法(鎖住 Class 對象)
public static synchronized void staticMethod() { ... }

優缺點

  • ✅ 簡單、語義清晰、JVM 優化成熟(偏向鎖、輕量級鎖、鎖消除等)
  • ❌ 競爭激烈時上下文切換開銷大
  • ❌ 持有鎖導致其他線程阻塞
  • ❌ 優先級反轉風險

方案二:CAS 無鎖機制與原子類

CAS(Compare And Swap)原理

三個操作數:

  • V:內存值
  • A:預期舊值
  • B:新值

當且僅當 V == A 時,原子性將 V 更新為 B,否則不動作並返回失敗。現代 CPU 提供指令級支持(如 x86 CMPXCHG),Java 通過 Unsafe.compareAndSwapInt 本地方法調用。

AtomicInteger 核心源碼解析

private volatile int value;  // volatile 保證可見性

public final int get() {
    return value;
}

public final int incrementAndGet() {
    for (;;) {  // 自旋
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

關鍵點

  • volatile:禁止指令重排,強制從主內存讀寫,保證可見性
  • 自旋重試:CAS 失敗循環重試,無阻塞、無上下文切換
  • 適用於低競爭、短臨界區場景

鎖 vs CAS 選型指南

場景推薦方案理由
高競爭、複雜邏輯synchronized / ReentrantLock避免自旋浪費 CPU,支持條件變量
低競爭、單變量操作AtomicInteger / LongAdder無鎖、吞吐高
計數器、統計LongAdder (Java 8+)分段累加,高併發下優於 AtomicLong
復雜條件同步ReentrantLock + Condition支持公平鎖、可中斷、多條件

進階:volatile 的幸福線

volatile 僅保證單次讀寫的原子性與可見性,不保證複合操作原子性(如 i++、check-then-act)。複合操作需配合鎖或原子類。

總結

理解 JMM、內置鎖優化演進、CAS 硬件語義與原子類實現,是寫出高併發正確代碼的基石。實際開發中:優先用高級併發工具,必要時才手寫同步。

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