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

Redis 分布式鎖實戰:基於 SETNX 的高可用實現與避坑指南

     編輯:Java 綜合教學

為什麼選擇 SETNX 實現分布式鎖?

Redis 的 SETNX(SET if Not eXists)命令具有原子性,天然適合作為分布式鎖的基礎原語。但單純的 SETNX key value 存在「鎖無法過期釋放」風險,需結合過期時間與獲取邏輯完善。

生產級代碼實現(含鎖超時、死鎖檢測、自動續期思路)

private static final String LOCK_KEY = "dist:lock:";
private static final long LOCK_TIMEOUT_MS = 60 * 60 * 1000L; // 1 小時

/**
 * 獲取分布式鎖
 * @param businessKey 業務鍵(如訂單ID)
 * @return true 獲取成功,false 獲取失敗
 */
public boolean tryLock(String businessKey) {
    String key = LOCK_KEY + businessKey;
    long expiresAt = System.currentTimeMillis() + LOCK_TIMEOUT_MS + 1L;

    // 1. 嘗試直接獲取鎖
    Long acquired = jedis.setnx(key, String.valueOf(expiresAt));
    if (acquired == 1L) return true; // 成功

    // 2. 獲取失敗,檢查現有鎖是否過期
    String currentVal = jedis.get(key);
    if (currentVal == null) return tryLock(businessKey); // 極罕見並發:鎖剛被釋放,遞歸重試

    long existingExpires = Long.parseLong(currentVal);
    if (existingExpires > System.currentTimeMillis()) {
        return false; // 鎖未過期,獲取失敗
    }

    // 3. 鎖已過期,嘗試用 GETSET 原子覆蓋並檢查舊值
    String oldVal = jedis.getSet(key, String.valueOf(expiresAt));
    if (oldVal == null) return true; // 極罕見:獲取期間鎖被釋放

    long oldExpires = Long.parseLong(oldVal);
    return oldExpires <= System.currentTimeMillis(); // 只有舊值也過期,才算搶佔成功
}

/**
 * 釋放鎖(需確保是鎖持有者才能釋放,生產環境建議用 Lua 腳本保證原子性)
 */
public void unlock(String businessKey) {
    String key = LOCK_KEY + businessKey;
    // 簡化版:直接刪除。生產環境請用 Lua 腳本判斷 value 後再 del
    jedis.del(key);
}

關鍵細節解析

  1. value 存儲絕對過期時間戳:而非相對秒數,避免客戶端時鐘不同步導致誤判。
  2. GETSET 原子覆蓋:解決「檢查過期 → 覆蓋」非原子導致的併發問題。
  3. 雙重過期檢查:先讀後 GETSET,確保只有舊鎖確實過期才能搶佔。
  4. 鎖超時時間設計:必須大於業務邏輯最大執行時間,防止業務未完成鎖自動釋放。

生產環境必做增強

  • Lua 腳本保證釋放原子性:if redis.call("get",KEYS[1])==ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
  • 鎖自動續期:後台線程定期延長 value 過期時間,防止長任務鎖失效(Redisson 已內置)。
  • 使用 Redisson:除非極簡場景,強烈建議直接用 Redisson 的 RLock,實現了看門狗、可重入、紅鎖等完整功能。
⚠️ 本文代碼為教學演示核心邏輯,高併發生產環境請直接使用 Redisson 或成熟分布式鎖框架。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved