详细分析Redisson的分布式锁

# Redisson中的锁续期机制

![](https://pic.it1024doc.com/cnblogs/202412/36983da33f1f3be64349456865ea42d7.png)

## 看门狗机制的启用时机

在Redisson框架中,看门狗(watchdog)是一个用于维护锁状态的重要特性,其启用与否依赖于锁超时时间的设置。

1. **lock() 方法与看门狗机制**:
   - 当调用不带参数的`lock()`方法时,Redisson会自动启动看门狗机制。这是因为在没有指定锁超时时间的情况下,Redisson默认需要自动续期锁,以避免因客户端崩溃或其他异常情况导致的锁未释放问题。

2. **lock(long leaseTime, TimeUnit unit) 方法与看门狗机制**:
   - 如果在调用`lock()`方法时明确指定了锁的超时时间(例如`lock(5000, TimeUnit.SECONDS)`),Redisson则不会启动看门狗机制。这是因为已经设定了锁的确切过期时间,表明用户希望在指定时间内持有锁,而不需要自动续期。

3. **tryLock() 方法与看门狗机制**:
   - 使用`tryLock()`方法时,如果不传递`leaseTime`参数或传递的`leaseTime`不大于0,Redisson会启动看门狗机制。这是因为看门狗机制确保在锁持有期间自动续期,以保障业务逻辑能在锁释放前顺利完成。

## renewExpiration方法详解

在Redisson中,锁的续期是通过定时任务自动管理的,该机制定期检查锁的状态,并决定是否需要进行续期。

```java
private void renewExpiration() {
    // 1. 首先检查EXPIRATION_RENEWAL_MAP中是否存在锁的ExpirationEntry对象,如果不存在,则锁可能已被释放或过期,无需续期,直接返回
    ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (ee == null) {
        return;
    }

    // 2. 创建一个基于TimerTask的定时任务,每internalLockLeaseTime / 3的时间进行一次锁续期,即每10秒续期一次
    Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
        @Override
        public void run(Timeout timeout) throws Exception {
            // 从EXPIRATION_RENEWAL_MAP中获取锁的状态,如果锁已被释放,则无需续期
            ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
            if (ent == null) {
                return;
            }
            // 获取持有锁的线程ID,如果线程ID不存在,则锁可能已被释放
            Long threadId = ent.getFirstThreadId();
            if (threadId == null) {
                return;
            }

            // 如果线程ID存在,则异步调用renewExpirationAsync(threadId)方法进行续期
            RFuture future = renewExpirationAsync(threadId);
            // 处理续期结果
            future.onComplete((res, e) -> {
                // 如果有异常发生,则记录错误日志
                if (e != null) {
                    log.error("Can't update lock " + getName() + " expiration", e);
                    return;
                }
                // 如果续期成功,则重新调用renewExpiration()方法进行下一次续期
                if (res) {
                    // reschedule itself
                    renewExpiration();
                }
            });
        }
    }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);

    ee.setTimeout(task);
}

详细步骤和逻辑分析

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

首先,从EXPIRATION_RENEWAL_MAP中获取当前锁的ExpirationEntry对象。如果该对象为null,说明锁可能已经被释放或过期,因此不需要进行续期,直接返回。

Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
    @Override
    public void run(Timeout timeout) throws Exception {
        ...
    }
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);

如果当前锁的ExpirationEntry对象不是null,就会继续往下执行,创建一个定时任务。这个定时任务的代码实现了一个锁的续期机制,具体步骤和逻辑分析如下:

在代码中,定时任务是通过commandExecutor.getConnectionManager().newTimeout(...)方法创建的,该任务的延迟时间设置为internalLockLeaseTime / 3毫秒,即每次续期的时间间隔。

```java
ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
if (ent == null)

版权声明:程序员胖胖胖虎阿 发表于 2024年12月27日 下午8:13。
转载请注明:详细分析Redisson的分布式锁 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...