<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          注解方式優(yōu)雅的實(shí)現(xiàn) Redisson 分布式鎖

          共 12077字,需瀏覽 25分鐘

           ·

          2023-11-09 04:38

          程序員的成長(zhǎng)之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享 
          關(guān)注


          閱讀本文大概需要 4 分鐘。

          來(lái)自:juejin.cn/post/7215142807861379109

          1前言

          日常開(kāi)發(fā)中,難免遇到一些并發(fā)的場(chǎng)景,為了保證接口執(zhí)行的一致性,通常采用加鎖的方式,因?yàn)榉?wù)是分布式部署模式,本地鎖Reentrantlock和Synchnorized這些就先放到一邊了,Redis的setnx鎖存在無(wú)法抱保證原子性的問(wèn)題就暫時(shí)擱且到一邊,直接上大招Redisson也是我最近開(kāi)發(fā)項(xiàng)目中基本都在用的緩存,并且也都是用它的分布式鎖機(jī)制。

          2Redisson分布式鎖常規(guī)使用

          關(guān)于Redisson的一些基本概念,本章就不做太詳細(xì)的說(shuō)明了,有興趣的小伙伴可以自己去了解下,主要說(shuō)下加鎖的常規(guī)使用,Redisson分布式鎖是基于Redis的Rlock鎖,實(shí)現(xiàn)了JavaJUC包下的Lock接口。

          Lock

          public void getLock(){
              //獲取鎖
              RLock lock = redisson.getLock("Lxlxxx_Lock");
              try {
                  // 2.加鎖
                  lock.lock();

              } catch (InterruptedException e) {
                  e.getStackTrace();
              } finally {
                  // 3.解鎖
                  lock.unlock();
                  System.out.println("Finally,釋放鎖成功");
              }

          getLock獲取鎖,lock.lock進(jìn)行加鎖,會(huì)出現(xiàn)的問(wèn)題就是lock拿不到鎖一直等待,會(huì)進(jìn)入阻塞狀態(tài),顯然這樣是不好的。

          TryLock

          返回boolean類(lèi)型,和Reentrantlock的tryLock是一個(gè)意思,嘗試獲取鎖,獲取到就返回true,獲取失敗就返回false,不會(huì)使獲不到鎖的線程一直處于等待狀態(tài),返回false可以繼續(xù)執(zhí)行下面的業(yè)務(wù)邏輯,當(dāng)然Ression鎖內(nèi)部也涉及到watchDog看門(mén)狗機(jī)制,主要作用就是給快過(guò)期的鎖進(jìn)行續(xù)期,主要用途就是使拿到鎖的有限時(shí)間讓業(yè)務(wù)執(zhí)行完,再進(jìn)行鎖釋放。

          RLock lock = redisson.getLock(name);
          try {

              if (lock.tryLock(2, 10, TimeUnit.SECONDS)) {
                  //執(zhí)行業(yè)務(wù)邏輯
              } else {
                  System.out.println("已存在");
              }
          } catch (InterruptedException e) {
              e.printStackTrace();
          }finally {
          //判斷當(dāng)前線程持有的鎖是不是處于鎖定狀態(tài),鎖定狀態(tài)再進(jìn)行釋放
              if (this.redissonLock.isHeldByCurrentThread(lockName)) {
                  this.redissonLock.unlock(lockName);
              }
          }

          3自定義注解實(shí)現(xiàn)鎖機(jī)制

          通常我們都會(huì)將redisson實(shí)例注入到方法類(lèi)里面,然后調(diào)用加鎖方法進(jìn)行加鎖,如果其他業(yè)務(wù)方法也需要加鎖執(zhí)行,將會(huì)產(chǎn)生很多重復(fù)代碼,由此采用AOP切面的方式,只需要通過(guò)注解的方式就能將方法進(jìn)行加鎖處理。

          自定義注解

          @Documented
          @Inherited
          @Retention(RetentionPolicy.RUNTIME)
          @Target({ElementType.METHOD})
          public @interface DistributedLock {
              String key() default "";

              int leaseTime() default 10;

              boolean autoRelease() default true;

              String errorDesc() default "系統(tǒng)正常處理,請(qǐng)稍后提交";

              int waitTime() default 1;
          }

          切面類(lèi)實(shí)現(xiàn)

          @Aspect
          @Component
          public class DistributedLockHandler {
              private static final Logger log = LoggerFactory.getLogger(DistributedLockHandler.class);
              @Autowired
              RedissonLock redissonLock;

              public DistributedLockHandler() {
              }

              @Around("@annotation(distributedLock)")
              public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
                  String lockName = this.getRedisKey(joinPoint, distributedLock);
                  int leaseTime = distributedLock.leaseTime();
                  String errorDesc = distributedLock.errorDesc();
                  int waitTime = distributedLock.waitTime();

                  Object var8;
                  try {
                      boolean lock = this.redissonLock.tryLock(lockName, (long)leaseTime, (long)waitTime);
                      if (!lock) {
                          throw new RuntimeException(errorDesc);
                      }

                      var8 = joinPoint.proceed();
                  } catch (Throwable var12) {
                      log.error("執(zhí)行業(yè)務(wù)方法異常", var12);
                      throw var12;
                  } finally {
                      if (this.redissonLock.isHeldByCurrentThread(lockName)) {
                          this.redissonLock.unlock(lockName);
                      }

                  }

                  return var8;
              }


              /**
               *  獲取加鎖的key
               * @param joinPoint
               * @param distributedLock
               * @return
               */
              private String getRedisKey(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
                  String key = distributedLock.key();
                  Object[] parameterValues = joinPoint.getArgs();
                  MethodSignature signature = (MethodSignature)joinPoint.getSignature();
                  Method method = signature.getMethod();
                  DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
                  String[] parameterNames = nameDiscoverer.getParameterNames(method);
                  if (StringUtils.isEmpty(key)) {
                      if (parameterNames != null && parameterNames.length > 0) {
                          StringBuffer sb = new StringBuffer();
                          int i = 0;

                          for(int len = parameterNames.length; i < len; ++i) {
                              sb.append(parameterNames[i]).append(" = ").append(parameterValues[i]);
                          }

                          key = sb.toString();
                      } else {
                          key = "redissionLock";
                      }

                      return key;
                  } else {
                      SpelExpressionParser parser = new SpelExpressionParser();
                      Expression expression = parser.parseExpression(key);
                      if (parameterNames != null && parameterNames.length != 0) {
                          EvaluationContext evaluationContext = new StandardEvaluationContext();

                          for(int i = 0; i < parameterNames.length; ++i) {
                              evaluationContext.setVariable(parameterNames[i], parameterValues[i]);
                          }

                          try {
                              Object expressionValue = expression.getValue(evaluationContext);
                              return expressionValue != null && !"".equals(expressionValue.toString()) ? expressionValue.toString() : key;
                          } catch (Exception var13) {
                              return key;
                          }
                      } else {
                          return key;
                      }
                  }
              }
          }

          具體使用

          圖片
          方法頭加自定義注解,key參數(shù)代表需要加鎖的key,errorDesc獲取鎖失敗提示報(bào)錯(cuò)信息。
          這邊我將項(xiàng)目通過(guò)修改端口啟動(dòng)了兩個(gè)服務(wù),分別是8460和8461
          圖片
          圖片
          通過(guò)postman調(diào)用這兩個(gè)服務(wù),模擬兩個(gè)服務(wù)同時(shí)獲取一把鎖的場(chǎng)景,其中一個(gè)服務(wù)拿到鎖,另外一個(gè)服務(wù)獲取鎖失敗。
          圖片
          可以看到端口8460服務(wù)先拿到鎖,8461服務(wù)tryLock獲取鎖失敗,實(shí)現(xiàn)了加鎖邏輯。
          圖片
          圖片

          4總結(jié)

          分布式鎖的使用場(chǎng)景還是需要多注意下,根據(jù)業(yè)務(wù)場(chǎng)景來(lái),并發(fā)量不大的情況下,其實(shí)沒(méi)有必要加,可能在移動(dòng)端操作比較頻繁的情況下需要注意并發(fā),目前我做的b端項(xiàng)目,通過(guò)簡(jiǎn)單接口冪等性操作就可以避免重復(fù)提交,切勿不要盲目加鎖,多少會(huì)影響一些性能。
          <END>

          推薦閱讀:

          面試官:如何使用 Dockerfile 去構(gòu)建自定義的 Docker 鏡像?問(wèn)倒一大片.....

          在國(guó)企和央企當(dāng)程序員體驗(yàn),太真實(shí)了。。

             
             
          互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

          內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper......等技術(shù)棧!

          ?戳閱讀原文領(lǐng)取!                                  朕已閱 

          瀏覽 243
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久夜色精品视频 | 久热视频在线 | 日韩三级影院 | 欧美精品在线观看 | 爱爱亚洲|