1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 12077字,需瀏覽 25分鐘

         ·

        2023-11-09 04:38

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


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

        來自:juejin.cn/post/7215142807861379109

        1前言

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

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

        關(guān)于Redisson的一些基本概念,本章就不做太詳細(xì)的說明了,有興趣的小伙伴可以自己去了解下,主要說下加鎖的常規(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)的問題就是lock拿不到鎖一直等待,會(huì)進(jìn)入阻塞狀態(tài),顯然這樣是不好的。

        TryLock

        返回boolean類型,和Reentrantlock的tryLock是一個(gè)意思,嘗試獲取鎖,獲取到就返回true,獲取失敗就返回false,不會(huì)使獲不到鎖的線程一直處于等待狀態(tài),返回false可以繼續(xù)執(zhí)行下面的業(yè)務(wù)邏輯,當(dāng)然Ression鎖內(nèi)部也涉及到watchDog看門狗機(jī)制,主要作用就是給快過期的鎖進(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í)例注入到方法類里面,然后調(diào)用加鎖方法進(jìn)行加鎖,如果其他業(yè)務(wù)方法也需要加鎖執(zhí)行,將會(huì)產(chǎn)生很多重復(fù)代碼,由此采用AOP切面的方式,只需要通過注解的方式就能將方法進(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;
        }

        切面類實(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)目通過修改端口啟動(dòng)了兩個(gè)服務(wù),分別是8460和8461
        圖片
        圖片
        通過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)景來,并發(fā)量不大的情況下,其實(shí)沒有必要加,可能在移動(dòng)端操作比較頻繁的情況下需要注意并發(fā),目前我做的b端項(xiàng)目,通過簡(jiǎn)單接口冪等性操作就可以避免重復(fù)提交,切勿不要盲目加鎖,多少會(huì)影響一些性能。
        <END>

        推薦閱讀:

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

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

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

        內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬并發(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)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            CaoPorn国产精品免费视频 | 欧美国产一二三区 | 欧美老妇操逼 | B想要XX在线观看 | 免费无遮挡 视频网站视频 | 精品999久久久一级毛片 | 少妇高潮a8198v在线观看 | 韩国三级中文字幕久久精品 | 高h繁交np双龙m人蛇漫画 | 欧美性爱自拍偷拍 |