1. Redisson簡介
Redisson是一個基于Redis的Java客戶端庫,提供了豐富的分布式對象和服務(如分布式鎖、信號量、Map等)。其核心優勢在于??簡化分布式鎖的實現??,并解決了原生Redis分布式鎖的常見問題(如死鎖、誤刪鎖等)。
2. Redisson分布式鎖核心特性
2.1 鎖類型
- ??可重入鎖(RLock)??:同一線程可重復獲取同一把鎖。
- ??公平鎖(FairLock)??:按請求順序分配鎖,避免饑餓現象。
- ??聯鎖(MultiLock)??:一次性鎖定多個資源。
- ??紅鎖(RedLock)??:基于多Redis實例的高可用鎖。
可重入鎖(RLock)
可重入鎖是Redisson最基礎的鎖類型,允許同一線程多次獲取同一把鎖而不會造成死鎖。其核心原理是:
- ??數據結構??:使用Redis的Hash結構存儲鎖信息,key為鎖名稱,field為線程標識(UUID+threadId),value為重入次數
- ??重入機制??:當線程首次獲取鎖時,計數器設為1;同一線程再次獲取時計數器遞增,釋放時遞減,直到計數器歸零才真正釋放鎖
- ??Lua腳本保證原子性??:加鎖和解鎖操作都通過Lua腳本實現,確保操作的原子性
// 獲取可重入鎖示例
RLock lock = redisson.getLock("myLock");
lock.lock(); // 第一次獲取鎖
try {lock.lock(); // 同一線程再次獲取鎖(重入)// 執行業務邏輯
} finally {lock.unlock(); // 釋放鎖(計數器減1)lock.unlock(); // 完全釋放鎖(計數器歸零)
}
公平鎖(FairLock)
公平鎖按照請求順序分配鎖資源,解決線程饑餓問題:
- ??排隊機制??:使用Redis的List結構實現等待隊列(redisson_lock_queue:{lockName}),ZSet結構記錄超時時間(redisson_lock_timeout:{lockName})
- ??公平獲取??:新線程獲取鎖時,必須檢查自己是否是隊列頭部,只有隊首線程才能獲取鎖
- ??超時清理??:定期清理隊列中超時的線程請求,避免無效等待
// 公平鎖使用示例
RLock fairLock = redisson.getFairLock("fairLock");
fairLock.lock();
try {// 公平執行業務邏輯
} finally {fairLock.unlock();
}
聯鎖(MultiLock)
聯鎖用于同時鎖定多個資源:
- ??原子性操作??:將多個RLock組合成一個鎖,所有鎖必須全部獲取成功才算成功
- ??嚴格互斥??:默認要求所有鎖都必須成功獲取(failedLocksLimit=0)
- ??適用場景??:如訂單系統中需要同時鎖定多個商品庫存的場景
// 聯鎖使用示例
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2, lock3);
multiLock.lock();
try {// 同時操作多個受保護資源
} finally {multiLock.unlock();
}
紅鎖(RedLock)
紅鎖是基于多Redis實例的高可用鎖:
- ??多數派原則??:在N個獨立Redis節點上獲取鎖,至少成功(N/2 +1)個才算獲取成功
- ??容錯機制??:即使部分節點故障,只要多數節點正常就能保證鎖可用
- ??解決主從問題??:避免主從切換導致的鎖失效問題
// 紅鎖使用示例
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.lock();
try {// 執行高可用要求的業務邏輯
} finally {redLock.unlock();
}
2.2 關鍵機制
- ??看門狗自動續期??:默認30秒檢查一次,若業務未完成則延長鎖過期時間。
- ??鎖超時釋放??:避免死鎖,支持手動設置
leaseTime
。 - ??非阻塞嘗試??:通過
tryLock(0, ...)
實現立即返回。
3. 代碼示例
3.1 基礎鎖使用
// 1. 獲取RedissonClient實例(需提前配置Redis連接)
RedissonClient redisson = Redisson.create(config);// 2. 獲取鎖對象(鎖鍵為"myLock")
RLock lock = redisson.getLock("myLock");try {// 3. 嘗試獲取鎖,waitTime=0表示不重試,leaseTime=10秒表示鎖自動釋放時間boolean isLocked = lock.tryLock(0, 10, TimeUnit.SECONDS);if (isLocked) {// 4. 執行業務邏輯System.out.println("鎖獲取成功,執行業務...");} else {System.out.println("鎖獲取失敗,直接返回");}
} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("線程被中斷");
} finally {// 5. 釋放鎖(需判斷當前線程是否持有鎖)if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();}
}
3.2 注解式鎖(Spring集成)
@Service
public class InventoryService {private int stock = 100;// 使用@Lock注解聲明分布式鎖(鎖鍵為"decreaseStockLock")@Lock(name = "decreaseStockLock")public void decreaseStock() {if (stock > 0) {stock--;System.out.println("庫存扣減成功,剩余: " + stock);}}
}
4. 最佳實踐
- ??避免鎖過期??:若業務耗時不確定,建議不設置
leaseTime
(啟用看門狗)。 - ??防誤刪鎖??:在
unlock()
前校驗鎖持有者(isHeldByCurrentThread()
)。 - ??非阻塞場景??:使用
tryLock(0, ...)
快速失敗。
5.對比總結
特性 | 可重入鎖 | 公平鎖 | 聯鎖 | 紅鎖 |
---|---|---|---|---|
核心特點 | 同一線程可重復獲取 | 按請求順序分配 | 同時鎖定多個資源 | 多節點高可用 |
數據結構 | Hash結構 | Hash+List+ZSet | 多個RLock組合 | 多個獨立節點鎖 |
適用場景 | 一般并發控制 | 避免線程饑餓 | 多資源原子操作 | 高可用要求場景 |
性能影響 | 低 | 中等(需維護隊列) | 高(需獲取所有鎖) | 高(多節點通信) |
參加:騰訊元寶
?