利用redis实现 分布式锁

利用redis实现 分布式锁

 

 1.给需要添加锁的地方添加锁

    @GetMapping("/get")
    public String test(HttpServletRequest request) throws InterruptedException {

        System.out.println("begin to do");

        String requestId = request.getSession().getId();
        String lockName = "Lock_Common_Dict_test";
        System.out.println("requestId " + requestId);

        boolean flag = this.authorityStore.tryGetDistributedLock(new Memo.Builder(lockName).value(requestId).expireTime(-1).build());
        try{
            if(flag) {
                Integer testKeyNum = (Integer) this.authorityStore.get("testKey");
                System.out.println("testKey " + testKeyNum);
                Thread.sleep(10000);
                if (testKeyNum < 1) {
                    System.out.println("testKeyNum < 0> will return");
                    return "testKeyNum < 0 will return;";
                }

                int i = 2/0;

                --testKeyNum;
                System.out.println("complete testkey ++");

                this.authorityStore.save(new Memo.Builder("testKey").value(testKeyNum).expireTime(10000).build());

                return "success;";
            } else{
                return "can not call now";
            }
        }
        catch (Exception ex){
            logger.error("running error");
            ex.printStackTrace();
        }finally {
            this.authorityStore.releaseDistributedLock(lockName, requestId);
        }
        return "can not call now";
    }

 

  2.redis添加锁,释放锁

    @Override
    public boolean tryGetDistributedLock(Memo memo) {
        String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        boolean beginDog = false;
        int expireTime = memo.expireTime();

        if (expireTime == -1) {
            expireTime = RedisUtil.lockWatchdogTimeout;
            beginDog = true;
        }

        Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(),
                Collections.singletonList(memo.key()), memo.value(), expireTime + "");
        boolean equals = SUCCESS.equals(result);
        if (equals && beginDog) {
            lockWatchdog.beginLockWatchdog(memo.key(), memo.value().toString());
        }
        return equals;
    }

    public boolean releaseDistributedLock(String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(),
                Collections.singletonList(lockKey), requestId);

        return SUCCESS.equals(result);
    }

  3.添加看门狗, 给未执行完的key延长时间

    //    watch dog
    public class LockWatchdog {

        private Timer TIMER = new Timer();

        /**
         * 开启一个看门狗
         *
         * @param lockKey
         * @return
         */
        public void beginLockWatchdog(String lockKey, String val) {
            renewExpiration(lockKey, val);
        }

        /**
         * 延长锁过期时间
         *
         * @param
         * @return
         */
        private void renewExpiration(String lockKey, String val) {
            TIMER.schedule(new TimerTask() {
                @Override
                public void run() {
                    try {
                        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end";
                        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
                        Object result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(),
                                Collections.singletonList(lockKey), val, String.valueOf(lockWatchdogTimeout));
                        if (Objects.equals(result, 1L)) {
                            renewExpiration(lockKey, val);
                        }
                    } catch (Exception e) {
                        logger.error("redis锁延长失败!", e);
                    }
                }
            }, lockWatchdogTimeout * 1000 / 3L);
        }

    }

 

posted @ 2023-05-16 18:55  goblinn  阅读(60)  评论(1编辑  收藏  举报