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

Java 多執行緒同步機制深度探究:從 synchronized 到 Lock 與 ThreadLocal

     編輯:Java 相關知識

為什麼需要同步?── 廁所裡的「門」

想像一間只能容納一人的公共廁所。沒有門時,大家衝進去會大亂鬥;裝上門並上鎖,第二人就必須等第一人出來才能進入。這就是互斥存取:共享資源(廁所)同一時間只允許一個執行緒(使用者)進入臨界區(如廁過程)。

在 Java 中,這把「門」就是物件鎖。每個物件天生擁有一把鎖,JVM 透過監視器實現互斥。

JVM 層面的鎖機制

  • 共享資料: 堆中實例變數、方法區類變數。區域變數在執行緒私有堆疊,無需同步。
  • 每個物件/類別關聯一個監視器,監視器持有鎖。
  • 執行緒進入 synchronized 區塊/方法時,自動嘗試獲取鎖;獲取成功計數器 +1,離開 -1,歸零釋放。
  • 可重入: 同一執行緒可重複獲取同一把鎖。
  • 類別鎖實為 Class 物件鎖: static synchronized 鎖住 Xxx.class。

三種傳統同步寫法

1. 同步實例方法

public synchronized void doTask() { ... }

鎖住 this。簡單但粒度較粗,整個方法互斥。

2. 同步區塊

public void doTask() {
    synchronized(lockObj) { // 指定鎖物件,縮小臨界區
        // 核心邏輯
    }
}

靈活控制鎖範圍,提升並發度。關鍵:多執行緒必須共用同一個 lockObj 實例。

3. 同步靜態方法

public static synchronized void staticTask() { ... }

鎖住 CurrentClass.class,所有實例共享這把鎖。

JDK 5+ 新選擇:java.util.concurrent.locks.Lock

Lock lock = new ReentrantLock();
lock.lock();
try {
    // 臨界區
} finally {
    lock.unlock(); // 必須在 finally 釋放
}

優勢:

  • 可中斷獲取鎖(lockInterruptibly())。
  • 可設定等待逾時(tryLock(timeout))。
  • 公平/非公平鎖可選。
  • 可搭配 Condition 實現精細等待/通知。

另類思路:ThreadLocal ── 空間換時間,無鎖並發

不共享、就不需同步。ThreadLocal 為每個執行緒提供獨立副本:

ThreadLocal threadLocal = new ThreadLocal<>();
threadLocal.set(1); // 當前執行緒專屬
Integer val = threadLocal.get();
  • 適用於「執行緒隔離」場景:資料庫連線、Session 上下文、交易 ID 追蹤。
  • 避免鎖競爭,極大提升高並發吞吐。
  • 注意:執行緒池環境下必須手動 remove() 防止記憶體洩漏。

同步策略選型對照

場景推薦方案
簡單共享變數、低競爭synchronized 方法/區塊
需可中斷、逾時、公平鎖、多條件變數ReentrantLock
執行緒獨享資料、高並發無狀態ThreadLocal
計數器、累加器等原子操作AtomicLong 等原子類別

總結

同步本質是協調共享資源存取順序。理解 JVM 物件鎖、監視器、可重入機制,才能正確選擇 synchronized、Lock 或 ThreadLocal。現代開發優先考慮無鎖設計(ThreadLocal、原子類別、不可變物件),必要時再用精細鎖控制,避免過度同步導致效能瓶頸與死鎖風險。

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