首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

分佈式環境下 Java synchronized 失效問題與解決方案

     編輯:程式設計疑難解答

問題場景

多台 Tomcat 叢集部署同一應用,某業務方法使用 `synchronized` 鎖定關鍵區段(如扣減庫存、生成單號)。開發者疑慮:synchronized 能否跨 JVM 實現互斥?

核心結論

synchronized 僅在單一 JVM 進程內有效,無法跨多台 Tomcat(多進程)實現互斥。

原理深度解析

分佈式鎖解決方案對比

層面說明
實現機制JVM 監視器鎖,基於物件頭 Mark Word,依賴共享堆記憶體中的物件頭狀態。
記憶體範圍每個 Tomcat 進程擁有獨立 JVM、獨立堆、獨立物件實例。物件頭鎖狀態不共享。
結果Tomcat A 鎖住 `this`,Tomcat B 看到的是另一個 `this` 實例,鎖狀態互不干擾,並發進入臨界區 → 數據不一致。
方案原理優點缺點適用場景
資料庫悲觀鎖`SELECT ... FOR UPDATE` / `UPDATE ... WHERE version = ?`無額外元件、強一致性、事務原生支援效能較低、連接池壓力大、死鎖風險低併發、強一致性要求高(訂單、扣款)
資料庫樂觀鎖版本號/時間戳 `UPDATE ... SET val=?, ver=ver+1 WHERE id=? AND ver=?`無鎖開銷、高併發友好衝突重試邏輯複雜、不適用長事務高併發、衝突率低(庫存、點贊)
Redis SETNX/Redisson`SET lock_key NX EX 30` + Lua 腳本續期/釋放高效能、支援可重入、公平鎖、紅鎖多節點需維護 Redis 叢集、網路分區風險高併發、微服務、分佈式任務調度
ZooKeeper 臨時有序節點建立臨時順序節點,最小序號獲取鎖,Watch 前驅節點強一致性、天然支援會話超時釋放、羊群效應可控寫效能受限、運維複雜、延遲較高配置管理、Leader 選舉、強一致協調
中央化協調服務獨立 Lock Service(gRPC/HTTP),內部用 ConcurrentHashMap + 條件變數邏輯集中、易擴展業務語義(鎖降級、超時回調)單點風險(需高可用)、額外網路跳轉內部中台、業務強相關鎖

推薦架構:Redis + Redisson(最通用)

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>:redisson-spring-boot-starter</artifactId>
  <version>3.23.0</version>
</dependency>

// 使用
@Autowired RedissonClient redisson;

public void deductStock(String productId) {
    RLock lock = redisson.getLock("stock:" + productId);
    boolean acquired = lock.tryLock(5, 10, TimeUnit.SECONDS); // 等待5s,租約10s自動續期
    if (!acquired) throw new RuntimeException("獲取鎖超時");
    try {
        // 臨界區:查庫存、扣減、寫入訂單
        stockService.deduct(productId);
    } finally {
        lock.unlock();
    }
}

資料庫層面輔助(最後防線)

  • 唯一索引防重:`UNIQUE KEY uk_order_no (order_no)` 防止生成重複單號。
  • 庫存扣減原子 SQL:`UPDATE product SET stock = stock - 1 WHERE id = ? AND stock > 0`,受影響行數 = 1 表示成功。
  • 樂觀鎖版本號:`UPDATE product SET stock = stock - 1, version = version + 1 WHERE id = ? AND version = ?`。

總結

synchronized 是進程內鎖,分佈式環境必須引入外部共享存儲(Redis/DB/ZK)實現跨進程互斥。選型原則:業務允許最終一致 → Redis;強一致/低併發 → DB 悲觀/樂觀鎖;協調/元數據 → ZK。並以資料庫約束作為最後兜底,構建多層防禦體系。

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