redisson中的看门狗机制

导读:本篇文章讲解 redisson中的看门狗机制,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

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);//省掉续期时间

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/96842.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!