Redisson分布式锁原理及自定义分布式锁

Redisson实现Redis分布式锁的底层原理

网上很多关于Redisson实现Redis的分布式原理的分析文章,我这里就不重复写了,看到的比较好的一遍文章如下http://t.csdn.cn/VagLh

基于Redis自定义实现分布式锁

鉴于目前基于redission的封装过重,并且开发同学使用redission需要自己释放锁,为了尽可能的避免问题,我们自己定义一套分布式锁模板。但是redis锁不一定靠谱(主从切换时有问题),如果考虑可靠性的话建议使用zk实现的分布式锁。

  1. 我没使用StringRedisTemplate进行key-value的操作;

    private final StringRedisTemplate stringRedisTemplate;
    
  2. 默认超时时间设置为5分钟;

    /**
    * 默认锁5分钟
    */
    private static final Duration LOCK_DURATION = Duration.ofMinutes(5L);
    
  3. 实现加锁方法

    public void lock() {
           log.debug("get distribute lock {}", key);
    
           while (true) {
               Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, LOCK_DURATION);
               if (success != null && success) {
                   WATCH_DOG_EXECUTOR.schedule(new WatchDogTask(this), DEFAULT_SLEEP_TIME, TimeUnit.MILLISECONDS);
                   break;
               }
           }
    

上面的方法使用了WatchDog,给锁续命;
5. WatchDog的实现

private static class WatchDogTask implements Runnable {
        private final RedisDistributeLock redisDistributeLock;

        public WatchDogTask(RedisDistributeLock redisDistributeLock) {
            this.redisDistributeLock = redisDistributeLock;
        }

        @Override
        public void run() {
            if (redisDistributeLock.isWatchDogFinished()) {
                return;
            }

            log.debug("expire distribute lock {}", redisDistributeLock.key);

            Boolean expireResult = false;
            try {
                expireResult = redisDistributeLock.stringRedisTemplate.execute(
                        EXPIRE_SCRIPT,
                        Arrays.asList(redisDistributeLock.key),
                        redisDistributeLock.uuid,
                        "300"
                );
            }
            catch (Exception e) {
                log.error("expire key {} error", redisDistributeLock.key, e);
            }

            if (expireResult != null && expireResult && !redisDistributeLock.isWatchDogFinished()) {
                WATCH_DOG_EXECUTOR.schedule(new WatchDogTask(this.redisDistributeLock), DEFAULT_SLEEP_TIME, TimeUnit.MILLISECONDS);
            }
        }
    }

锁续命使用的是lua脚本,即看门狗中用到的EXPIRE_SCRIPT变量;

if redis.call('get',KEYS[1]) == ARGV[1] then
  redis.call('expire', KEYS[1], ARGV[2])
  return 1
else
  return 0
end
  1. 释放锁的方法

    public void unlock() {
        log.debug("release distribute lock {}", key);
        try {
            stringRedisTemplate.execute(RELEASE_SCRIPT, Arrays.asList(key), uuid);
        }
        catch (Exception e) {
            log.error("release lock {} error", key, e);
        }
    }
    

    执行的lua脚本(RELEASE_SCRIPT变量)

    if redis.call('get',KEYS[1]) == ARGV[1] then
        redis.call('del',KEYS[1])
        return 1
    else
        return 0
    end
    

大家可能发现了,上述代码实现的锁不支持可重入;因为从使用场景来看,可重入锁并没有使用的必要,也没必要实现可重入锁,而且增加了可重入锁实现起来也麻烦;但是和jdk的多线程可重入锁还是有却别的,那个的可重入锁是必要的;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值