RedissonLock-tryLock-续期

redisson版本3.16.6

1.什么是看门狗

Redisson提供的分布式锁是支持锁自动续期的,也就是说,如果线程仍旧没有执行完,那么redisson会自动给redis中的目标key延长超时时间,这在Redisson中称之为 Watch Dog 机制。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

2.什么情况会续期

什么情况会续期,总结一句话:不传入leaseTime(锁自动释放时间),使用默认值-1

tryLock可传入参数有三个

lockName需要锁住的内容关键字

waitTime 获取锁最大等待时间,没有传-1

leaseTime锁自动释放时间,没有传-1

boolean tryLock 重载了三个方法,分别如下:

boolean tryLock(String lockName);

boolean tryLock(String lockName, long waitTime) throws InterruptedException;

boolean tryLock(String lockName, long waitTime, long leaseTime) throws InterruptedException;

从实现上看,使用才传参,不用,千万别主动写入-1,会对入参有校验。可以实现续期的情况只能使用前两个构造器,不能使用主动传入leaseTime的构造器。为什么这么说呢,源码如下:

方法都会调用tryLock获取锁,tryLock方法中调用tryAcquire方法

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
    long time = unit.toMillis(waitTime);
    long current = System.currentTimeMillis();
    long threadId = Thread.currentThread().getId();
    Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
    // lock acquired
    if (ttl == null) {
        return true;
    }
        ....省略

tryAcquire方法会调用tryAcquireAsync,源码如下:

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

        // lock acquired
        if (ttlRemaining == null) {
            if (leaseTime != -1) {
                internalLockLeaseTime = unit.toMillis(leaseTime);
            } else {
                scheduleExpirationRenewal(threadId);
            }
        }
    });
    return ttlRemainingFuture;
}

从源码上看,只有当leaseTime为-1时scheduleExpirationRenewal这个方法才会生效,这个方法会进行续期。

3.续期源码分析

启一个task任务进行锁的自动续期

scheduleExpirationRenewal()->renewExpiration()

private void renewExpiration() {
    ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (ee == null) {
        return;
    }

    // 启一个定时任务
    Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
        @Override
        public void run(Timeout timeout) throws Exception {
            ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
            if (ent == null) {
                return;
            }
            Long threadId = ent.getFirstThreadId();
            if (threadId == null) {
                return;
            }

            // 核心续期代码,执行lua脚本
            RFuture<Boolean> future = renewExpirationAsync(threadId);
            future.onComplete((res, e) -> {
                if (e != null) {
                    log.error("Can't update lock " + getRawName() + " expiration", e);
                    EXPIRATION_RENEWAL_MAP.remove(getEntryName());
                    return;
                }

                if (res) {
                    // renewExpirationAsync执行成功,进行递归调用,调用自己,就可以实现不停的续期
                    // 第一次执行这个函数,设置task任务,10s后执行task任务,刷新有效期,又重新设置一个task任务,10s后执行
                    renewExpiration();
                } else {
                    cancelExpirationRenewal(null);
                }
            });
        }
        // 定时任务是lockWatchdogTimeout的1/3时间去执行,就是每10s执行一次,renewExpirationAsync进行续期
    }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);

    ee.setTimeout(task);
}

### Redisson 中分布式锁的使用方法 #### 创建并初始化 Redisson 客户端实例 要使用 Redisson 的分布式锁,首先需要创建 `RedissonClient` 实例。这通常通过配置文件或编程方式完成。 ```java Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` #### 获取分布式锁对象 接着获取一个名为 `myLock` 的分布式锁对象: ```java RLock myLock = redisson.getLock("myLock"); ``` #### 加锁操作 可以调用不同的加锁方法来适应具体需求场景。对于简单的阻塞式加锁可直接调用无参版本的方法;如果希望指定超时时间,则传递相应的参数给有参版函数[^3]。 ```java // 尝试获得锁,默认一直等待直到成功为止 myLock.lock(); // 设置最大持有时间为 10 秒钟 myLock.lock(10, TimeUnit.SECONDS); try { // 执行受保护的关键区段代码... } catch (Exception e) { // 异常处理逻辑... } finally { // 不论是否发生异常都确保解锁 myLock.unlock(); } ``` #### 自动续期机制 为了避免因程序崩溃等原因造成的死锁现象,Redisson 提供了自动续期的功能。一旦设置了合理的看门狗间隔周期(默认为 30 秒),即使客户端意外终止也能保证锁最终会被安全释放。 #### 错误尝试与重试策略 考虑到网络波动等因素可能导致首次请求未能成功取得锁的情况,在实际应用中往往还需要加入适当的错误恢复措施,比如自定义的最大重试次数以及每次重试之间的延迟间隔等[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值