redisson中的看门狗机制

redis分布式锁演示代码:

public String hello() throws InterruptedException{
        //获取一把锁,名称相同,就是同一把锁
        RLock lock = redisson.getLock("my-lock");
        //lock.lock();
        lock.lock(10, TimeUnit.SECONDS);//自动解锁时间,一定要大于业务的执行时间
        //问题lock.lock(10, TimeUnit.SECONDS)在锁时间到了之后,不会自动续期
        try {
            System.out.println("加锁成功!");
            Thread.sleep(3000);
        }finally {
            lock.unlock();
        }

        return "hello";
    }
  1. lock.lock();此为一个阻塞式锁,默认锁的过期时间为30s,如果30s内业务代码还没有执行完,将在1/3看门狗时间后自动续期;
  2. lock.lock(10, TimeUnit.SECONDS);当我们使用此方法指定过期时间后,便又引发了一个问题, 当业务逻辑执行时间超过10s时,锁已经释放,此时如果还有其他线程访问,又可以得到锁; 且如上述代码中:
		try {
            System.out.println("加锁成功!");
            Thread.sleep(3000);
        }finally {
            lock.unlock();
        }

当业务逻辑在30s执行完成后,他删的锁是下一个线程的锁,而不是它自己的锁;此时便会报出如下错误:此时
2,接下来,我们看一下他的源代码:
在这里插入图片描述
可以看到,当我们指定时间后,他会用我们指定的时间再次执行lock方法;
在这里插入图片描述
首先他会获取线程Id, 接着如果获取到锁,就直接返回,没有获取到就循环等待, 直至获取到锁;
我们再来看看tryAcquire方法:
在这里插入图片描述
他又调用了get方法, get方法里面又调用了tryAcquireAsync方法;

private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
        if (leaseTime != -1) {
            return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
        }
        RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
        ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
            if (e != null) {
                return;
            }

            // lock acquired
            if (ttlRemaining == null) {
                scheduleExpirationRenewal(threadId);
            }
        });
        return ttlRemainingFuture;
    }

leaseTime则是我们指定的10s, 如果没有传时间,他会调用如下lock方法,将时间设置为-1;
在这里插入图片描述

传时间

调用tryLockInnerAsync函数
在这里插入图片描述
此方法是向redis发送一个lua脚本去占位执行,

未传时间

private RFuture<Boolean> tryAcquireOnceAsync(long leaseTime, TimeUnit unit, long threadId) {
        if (leaseTime != -1) {
            return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_NULL_BOOLEAN);
        }
        RFuture<Boolean> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_NULL_BOOLEAN);
        ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
            if (e != null) {
                return;
            }

            // lock acquired
            if (ttlRemaining) {
                scheduleExpirationRenewal(threadId);
            }
        });
        return ttlRemainingFuture;
    }

它便会获取锁的看门狗时间getLockWatchdogTimeout()
在这里插入图片描述
可以看到,看门狗默认时间为30s; 如果占位成功! 就会继续监听
在这里插入图片描述
有异常直接返回, 没有异常根据代码,我们可以看到他将重新获取过期时间,
在这里插入图片描述
在renewExpiration方法中:
在这里插入图片描述
定时任务中的renewExpirationAsync()方法:
在这里插入图片描述
又是向redis发送lua脚本执行; 且它的internalLockLeaseTime又是看门狗时间,如下:
在这里插入图片描述
续期时间:
在这里插入图片描述
结论:

  • 如果我们传了时间,就发送给redis执行脚本, (如果不解锁)锁将在我们指定的时间内释放
  • 如果未指定锁的超时时间, 就使用30 * 1000看门狗时间

推荐使用传时间的lock方法,过期时间不要毫秒级别即可!

lock.lock(10, TimeUnit.SECONDS);//省掉续期时间

新开了公众号,欢迎大家关注交流,互相讨论!
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值