redis分佈式鎖(redisson)

redis分佈式鎖api:redisson

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.7.2</version>
</dependency>

redisson多線程執行流程:

 

注意點說明:

  • 線程一獲取鎖必須加等待獲取時間,持有鎖時間:在等待時間內沒有獲取鎖則失敗,防止無限等待造成死鎖,持有鎖時間:防止程序異常後沒有執行釋放鎖代碼使得該鎖一致有效,其他線程無法獲取鎖造成的死鎖。
  • 持有鎖時間必須大於獲取鎖後業務代碼執行時間,防止業務代碼還沒有執行完成就把鎖提前釋放的異常,但是生產上難免因爲網絡等問題造成 業務代碼還沒有執行完鎖的有效時間就到了的情況:針對這種情況redisson在線程獲取鎖成功後另外起了一個線程,在鎖到期後判斷業務代碼沒執行完就會延長鎖的時間
  • 獲取鎖對象時,需要加入redisKey的鎖對象標識,用於和其他業務的鎖對象做區分,防止釋放鎖時把別人的鎖釋放掉
  • 線程1獲取鎖成功後,線程2會while循環,自旋等待獲取鎖知道線程1釋放後獲取成功
  • 生產上redis一般不是單機的,採用集羣或者哨兵,場景:線程1獲取鎖成功後正在處理業務代碼,如果此時master宕機,系統啓用slave,鎖是不是會丟失,造成其他線程在線程1沒結束前就獲取到了鎖呢?解決:redisson中會把集羣或者哨兵中的鎖同步到每一個redis服務器中,防止這種情況的發生
  • 除了一般普通的鎖之外,redisson中還提供了讀寫鎖,用來解決多讀,少寫的情況:場景:N個線程在讀取資源,1個線程去修改,修改了一半發生了回滾,N個讀線程會不會讀取到修改了一般又回滾的髒數據呢,此時1個寫線程可以加寫鎖,N個讀線程可以加讀鎖,獲取寫鎖後所有的讀鎖會進入自旋等待,直到讀鎖主動或回滾釋放後,讀鎖才能獲繼續讀取資源。所有的讀鎖是共享鎖,不會互斥,所以多個讀線程不會有鎖等待,不會影響效率。
  • redisson底層採用的是LUA腳本來確保redis操作的原子性

具體使用:

@Autowired
@Lazy
private RedissonClient redissonClient;

public void lockTest() {
   // 生成redisKey常量
   String redisKey = "{redisPrefix}:" + "鎖的唯一標識(業務字段)";
   // 由redisKey獲取分佈式鎖對象
   RLock lock = redissonClient.getLock(redisKey);
   try {
     // 獲取鎖
     // 參數1:獲取鎖等待的時間,參數2:持有鎖的時間,參數3:時間單位,返回值:是否獲取成功  
     boolean lockResult = lock.tryLock("5", "10",TimeUnit.SECONDS); 
   } catch (Exception e) {
     // 獲取鎖過程中的異常處理
     log.error("獲取鎖異常,redisKey:{},異常信息:{}",redisKey,e);
     throw new serviceException("錯誤碼");
   }
   // 判斷是否獲取成功
   if (!lockResult) {
     log.error("獲取鎖超時或失敗,redisKey:{},異常信息:{}",redisKey,e);
     throw new serviceException("錯誤碼")
   }
   // 開始執行業務代碼,這裏的代碼越少越好
   try {
   } catch (Exception e) {
     log.error("處理業務異常代碼失敗,{}",e)
     thorw new serviceException("錯誤碼")
   } finally {
     // 釋放鎖:必須判斷是否是自己的鎖,防止把別人的鎖釋放掉
     lock.unlock();
   }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章