# 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)
相关文章
暂无评论...