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 重载了三个方法,分别如下:
java
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方法
java
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,源码如下:
java
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()
java
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);
}