Java基於redis實現分布式鎖(SpringBoot)


前言

分布式鎖,其實原理是就是多台機器,去爭搶一個資源,誰爭搶成功,那么誰就持有了這把鎖,然后去執行后續的業務邏輯,執行完畢后,把鎖釋放掉。

可以通過多種途徑實現分布式鎖,例如利用數據庫(mysql等),插入一條記錄(唯一索引),誰插入成功,誰就持有鎖;還可通過zookeeper來實現分布式鎖,誰創建節點成功,誰就持有鎖。本文介紹通過redis來實現分布式鎖。

本文使用springboot提供的RedisTemplate來操作redis,可以參考我之前的文章【快學springboot】13.操作redis之String數據結構,這里對使用RedisTemplate來操作redis做了介紹。當然也可以直接使用jedis來操作redis,大家可以參考下jedis的文檔,使用上都是大同小異的。

實現分布式鎖的步驟

第一步:通過redis的setnx方式(不存在則設置),往redis上設置一個帶有過期時間的key,如果設置成功,則獲得了分布式鎖。這里設置過期時間,是防止在釋放鎖的時候出現異常導致鎖釋放不掉。

第二步:執行完業務操作之后,刪除該鎖。

實現

新建一個DistributedLock.class,注入StringRedisTemplate。

@Component
public class DistributedLock {
​
 @Autowired
 private StringRedisTemplate redisTemplate;
​
}

獲得鎖

/**
 * 獲得鎖
 */
 public boolean getLock(String lockId, long millisecond) {
 Boolean success = redisTemplate.opsForValue().setIfAbsent(lockId, "lock",
 millisecond, TimeUnit.MILLISECONDS);
 return success != null && success;
 }

setIfAbsent方法,就是當鍵不存在的時候,設置,並且該方法可以設置鍵的過期時間。該方法對應到redis的原生命令就是:

SET lockId content PX millisecond NX 

至於設置多少的過期時間合適,這個是沒有定論的,需要根據真是的業務場景來衡量。

釋放鎖

當處理完業務邏輯后,需要手動的把鎖釋放掉。

 public void releaseLock(String lockId) {
 redisTemplate.delete(lockId);
 }

釋放鎖的操作比較簡單,直接刪除之前設置的鍵即可。其實,基於redis實現分布式鎖的方式,在釋放鎖的時候,是存在釋放失敗的風險的(比如網路抖動什么的),這也是為什么在設置鎖的時候需要設置過期時間的原因,可以防止在出現異常的時候,鎖會自動的消失掉。同時,我們也可以增加幾次失敗之后的重試機制。

測試

新建一個BusinessTask.java,代碼如下:

@Component
public class BusinessTask {
​
 private final static String LOCK_ID = "happyjava";
​
 @Autowired
 DistributedLock distributedLock;
​
 @Scheduled(cron = "0/10 * * * * ? ")
 public void doSomething() {
 boolean lock = distributedLock.getLock(LOCK_ID, 10 * 1000);
 if (lock) {
 System.out.println("執行任務");
 distributedLock.releaseLock(LOCK_ID);
 } else {
 System.out.println("沒有搶到鎖");
 }
 }
​
}

這里使用了springboot的Scheduled注解來實現定時任務,該cron表達式的意思是每10秒鍾,執行一次任務,然后我們啟動兩次該項目,觀察一段時間執行結果:

第一個springboot任務:

基於redis實現分布式鎖(Java)

第二個springboot任務:

基於redis實現分布式鎖(Java)

兩個任務在交替的執行任務,證明了同一時刻只有一個應用持有了鎖。

總結

本文主要介紹了如何使用Java代碼(springboot的restTemplate)實現Redis分布式鎖,對於加鎖和解鎖也分別給出了示例代碼。其實我們還可以嘗試使用Redisson實現分布式鎖,這是Redis官方提供的Java組件,這個后續再介紹吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM