<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Java-函數(shù)式編程-實(shí)現(xiàn)分布式鎖工具

      該業(yè)務(wù)適用場景:

      • 分布式環(huán)境下的資源互斥訪問

      • 防止重復(fù)執(zhí)行(如定時(shí)任務(wù))

      • 庫存扣減等需要強(qiáng)一致性的操作

      一. 背景

      在開發(fā)過程中需要使用到分布式鎖的時(shí)候(以redisson為例). 一般會通過初始化RedissonClient配置, 然后在需要的地方使用. 當(dāng)使用的多的時(shí)候會發(fā)現(xiàn), 代碼中充斥著相似的代碼結(jié)構(gòu), 例如

      String lockKey = RedisBaseKeyEnum.APP_USER_REGISTRY_VERIFY_CODE_KEY_LOCK.buildKey(account);
      RLock lock = redissonClient.getLock(lockKey);
      try {
          if (lock != null && !lock.isLocked() && lock.tryLock(0, 60L, TimeUnit.SECONDS)) {
              // some biz
          }
      } catch (InterruptedException e) {
          LOG.error("加鎖失敗,key:{}, account:{}", lockKey, account, e);
          Thread.currentThread().interrupt();
          throw new BizException(BizErrorCode.VERIFY_CODE_SENDER_ERROR);
      } finally {
          if (lock.isLocked() && lock.isHeldByCurrentThread()) {
              lock.unlock();
          }
      }
      

      簡單的加鎖過程類似于上面的代碼. 所以為了提升代碼的可復(fù)用性, 降低重復(fù)代碼, 提高系統(tǒng)可維護(hù)性. 我們可以通過Java中的函數(shù)式編程, 將重復(fù)的代碼塊抽象出一個(gè)模板. 然后具體的業(yè)務(wù)通過作為方法入?yún)?/strong> 來實(shí)現(xiàn).

      二. 核心點(diǎn)

      1. 抽象分布式鎖業(yè)務(wù)

      2. 使用@FunctionalInterface注解將需要注入的業(yè)務(wù)抽象出來

      3. 注入使用

      三. 實(shí)現(xiàn)方式

      1. 定義函數(shù)式接口 @FunctionalInterface

      ============================= 加鎖業(yè)務(wù) 有返回值 ===============================
      package com.sj.utils.lock.func;
      
      @FunctionalInterface
      public interface LockTask {
          void run() throws Exception; // 沒有入?yún)⒌姆椒?}
      ============================= 加鎖業(yè)務(wù)沒有返回值 ===============================
      package com.sj.utils.lock.func;
      
      @FunctionalInterface
      public interface LockTask {
      
          void run() throws Exception; // 沒有入?yún)⒌姆椒?
      }
      
      1. 定義Redisson分布式鎖類型枚舉

      package com.sj.utils.lock;
      
      public enum RLockType {
          REENTRANT,       // 可重入鎖
          FAIR,            // 公平鎖
          READ,            // 讀鎖
          WRITE,           // 寫鎖
          TRY,             // 嘗試獲取鎖
          TRY_WITH_FAIL    // 嘗試失敗鎖 tryLock中waitTime為0
      }
      

      然后

      ===========================RLockSimpleUtil========================
      public RLock getLock(String lockKey, RLockType lockType) {
          switch (lockType) {
              case TRY:
              case REENTRANT:
              case TRY_WITH_FAIL:
                  return redissonClient.getLock(lockKey);
              case FAIR:
                  return redissonClient.getFairLock(lockKey);
              case READ:
                  return redissonClient.getReadWriteLock(lockKey).readLock();
              case WRITE:
                  return redissonClient.getReadWriteLock(lockKey).writeLock();
              default:
                  throw new IllegalArgumentException("Unknown lock type: " + lockType);
          }
      }
      
      1. 定義RLockSimpleUtil

      package com.sj.utils.lock;
      
      import com.sj.utils.lock.func.LockException;
      import com.sj.utils.lock.func.LockTask;
      import com.sj.utils.lock.func.LockTaskWithResult;
      import org.redisson.api.RLock;
      import org.redisson.api.RedissonClient;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.stereotype.Component;
      
      import java.util.concurrent.TimeUnit;
      
      @Component
      public class RLockSimpleUtil {
          private final Logger log = LoggerFactory.getLogger(RLockSimpleUtil.class);
          private final RedissonClient redissonClient;
      
          // 鎖默認(rèn)參數(shù)
          private final long DEFAULT_WAIT_TIME = 5;       // 秒
          private final long DEFAULT_LEASE_TIME = 30;     // 秒
          private final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;
      
          public RLockSimpleUtil(RedissonClient redissonClient) {
              this.redissonClient = redissonClient;
          }
      
          /**
           * 執(zhí)行帶返回值的任務(wù),默認(rèn)使用可重入鎖
           *
           * @param lockKey 鎖鍵
           * @param task    任務(wù)
           * @param <T>     任務(wù)返回值類型
           * @return 任務(wù)返回值
           */
          public <T> T executeWithResult(String lockKey, LockTaskWithResult<T> task) {
              return executeWithResult(lockKey, RLockType.REENTRANT, DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, DEFAULT_TIME_UNIT, task);
          }
      
          /**
           * 執(zhí)行帶返回值的任務(wù),支持指定鎖類型和超時(shí)時(shí)間
           *
           * @param lockKey   鎖鍵
           * @param lockType  鎖類型
           * @param waitTime  等待時(shí)間
           * @param leaseTime 租約時(shí)間
           * @param unit      時(shí)間單位
           * @param lockTask  任務(wù)
           * @param <T>       任務(wù)返回值類型
           * @return 任務(wù)返回值
           */
          public <T> T executeWithResult(String lockKey,
                                         RLockType lockType,
                                         long waitTime,
                                         long leaseTime,
                                         TimeUnit unit,
                                         LockTaskWithResult<T> lockTask) {
              RLock lock = getLock(lockKey, lockType);
              boolean acquired = false;
              try {
                  acquired = lock.tryLock(waitTime, leaseTime, unit);
                  if (!acquired) {
                      throw new LockException("Failed to acquire lock: " + lockKey);
                  }
                  return lockTask.runWithResult();
              } catch (InterruptedException e) {
                  Thread.currentThread().interrupt();
                  throw new LockException("Lock acquisition interrupted", e);
              } catch (Exception e) {
                  throw new RuntimeException(e);
              } finally {
                  unlockQuietly(lock, acquired);
              }
          }
      
          /**
           * 執(zhí)行無返回值的任務(wù),默認(rèn)使用可重入鎖
           *
           * @param lockKey  鎖鍵
           * @param lockTask 任務(wù)
           */
          public void execute(String lockKey, LockTask lockTask) {
              execute(lockKey, RLockType.REENTRANT, DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, DEFAULT_TIME_UNIT, lockTask);
          }
      
          /**
           * 執(zhí)行無返回值的任務(wù),支持指定鎖類型和超時(shí)時(shí)間
           *
           * @param lockKey   鎖鍵
           * @param lockType  鎖類型
           * @param waitTime  等待時(shí)間
           * @param leaseTime 租約時(shí)間
           * @param timeUnit  時(shí)間單位
           * @param lockTask  任務(wù)
           */
          public void execute(String lockKey, RLockType lockType, long waitTime, long leaseTime, TimeUnit timeUnit, LockTask lockTask) {
              RLock lock = getLock(lockKey, lockType);
              boolean acquired = false;
              try {
                  acquired = lock.tryLock(waitTime, leaseTime, timeUnit);
                  if (!acquired) {
                      throw new LockException("Failed to acquire lock: " + lockKey);
                  }
                  lockTask.run();
              } catch (InterruptedException e) {
                  Thread.currentThread().interrupt();
                  throw new LockException("Interrupted while trying to acquire lock: " + lockKey);
              } catch (Exception e) {
                  throw new RuntimeException(e);
              } finally {
                  unlockQuietly(lock, acquired);
              }
          }
      
          /**
           * 獲取指定鎖類型的鎖實(shí)例
           *
           * @param lockKey  鎖鍵
           * @param lockType 鎖類型
           * @return 鎖實(shí)例
           */
          public RLock getLock(String lockKey, RLockType lockType) {
              switch (lockType) {
                  case TRY:
                  case REENTRANT:
                  case TRY_WITH_FAIL:
                      return redissonClient.getLock(lockKey);
                  case FAIR:
                      return redissonClient.getFairLock(lockKey);
                  case READ:
                      return redissonClient.getReadWriteLock(lockKey).readLock();
                  case WRITE:
                      return redissonClient.getReadWriteLock(lockKey).writeLock();
                  default:
                      throw new IllegalArgumentException("Unknown lock type: " + lockType);
              }
          }
      
          /**
           * 安靜地解鎖鎖實(shí)例
           *
           * @param lock     鎖實(shí)例
           * @param acquired 是否成功獲取鎖
           */
          private void unlockQuietly(RLock lock, boolean acquired) {
              try {
                  if (acquired && lock.isLocked() && lock.isHeldByCurrentThread()) {
                      lock.unlock();
                  }
              } catch (Exception e) {
                  if (lock != null && lock.isHeldByCurrentThread()) {
                      log.warn("Error unlocking: {} ", e.getMessage(), e);
                      lock.unlock();
                  }
              }
          }
      
      
      }
      

      四. 使用方式

      1. 在具體的業(yè)務(wù)中注入RLockSimpleUtil

      2. 根據(jù)具體業(yè)務(wù), 直接調(diào)用util中的具體方法, 例如一個(gè)簡單的加鎖業(yè)務(wù):

      @Override
      public ShortAddressResult acquire(ShortAddressTypeEnum type, Long householdId, Integer count) {
          String key = RedisBaseKeyEnum.DEVICE_SHORT_ADDRESS_LIST_CACHE_KEY_LOCK
                              .buildKey(householdId.toString());
          return rLockSimpleUtil.executeWithResult(
                  key,
                  RLockType.FAIR,
                  30,
                  3,
                  TimeUnit.SECONDS,
                  // 下方執(zhí)行具體的加鎖業(yè)務(wù)
                  () -> {
                      String cacheKey = getCacheKey(type, householdId);
                      return shortAddressPoolService.acquire(type, cacheKey, householdId, count);
                  });
      }
      

      五. 補(bǔ)充

      1. Java內(nèi)置的函數(shù)式接口:

      • Runnable - 無參數(shù)無返回值

      • Supplier - 無參數(shù)有返回值

      • Consumer - 有參數(shù)無返回值

      • Function<T,R> - 有參數(shù)有返回值

      • Predicate - 有參數(shù)返回布爾值

      1. 潛在問題

      2. Redis 單點(diǎn)依賴

        1. 依賴 Redis 可用性

        2. Redis 故障會影響所有鎖操作

      3. 鎖超時(shí)風(fēng)險(xiǎn)

        1. 固定租約時(shí)間可能不適合所有場景

        2. 長時(shí)間任務(wù)可能導(dǎo)致鎖提前釋放

      4. 性能考慮

        1. 每次鎖操作都需要網(wǎng)絡(luò)通信

        2. 高并發(fā)場景下可能成為瓶頸

      5. 異常處理可能過于寬泛

      6. 缺少監(jiān)控指標(biāo)

        1. 沒有鎖獲取成功率統(tǒng)計(jì)

        2. 沒有鎖持有時(shí)間監(jiān)控

      posted @ 2025-10-31 09:35  你啊347  閱讀(8)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 靖安县| 亚洲真人无码永久在线| av小次郎网站| 欧美成人午夜性视频| 日韩精品一区二区高清视频| 国产精品久久久久久无毒不卡 | 激,情四虎欧美视频图片| jizzjizz少妇亚洲水多| 欧美老少配性行为| 三级网站视频在在线播放| 新丰县| 国产一区二区三区亚洲精品| 日韩精品中文字幕人妻| 成人午夜国产内射主播| 日本中文一二区有码在线| 午夜毛片不卡免费观看视频| 国产亚洲色婷婷久久99精品| 亚洲一区二区三区啪啪| 丁香五月婷激情综合第九色| 成人精品区| 国产精品国产三级国产专i| 国产熟女肥臀精品国产馆乱| 最新精品国偷自产在线| 无码人妻斩一区二区三区| 国产日韩AV免费无码一区二区三区| 边摸边吃奶边做爽动态| 深夜精品免费在线观看| 久久精品国产久精国产| 亚洲色大成网站WWW久久| 万年县| 女人腿张开让男人桶爽 | 人妻aⅴ无码一区二区三区| 久久亚洲日本激情战少妇| 成人深夜节目在线观看| 文中字幕一区二区三区视频播放 | 老师扒下内裤让我爽了一夜| 97在线视频人妻无码| 偷偷做久久久久免费网站| 少妇办公室好紧好爽再浪一点| 日韩一区二区三区女优丝袜| 亚洲a人片在线观看网址|