@Override
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();
// tryAcquire尝试获取锁,成功则返回null,失败则返回锁的剩余有效时间
Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
// lock acquired
if (ttl == null) {
//获取锁成功
return true;
}
// 剩余剩余等待时间 = 最大等待时间减去尝试获取锁过程消耗的时间
time -= System.currentTimeMillis() - current;
if (time <= 0) {
//剩余最大等待时间< 0 return false 获取锁失败 不再尝试获取
acquireFailed(waitTime, unit, threadId);
return false;
}
current = System.currentTimeMillis();
// 订阅当前线程id的通知,当锁被释放时,回发布通知。
CompletableFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
try {
// 阻塞当前线程等待获取通知结果
subscribeFuture.get(time, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// 没有获取到通知为false,!false为true 执行以下逻辑,取消订阅,返回false。
if (!subscribeFuture.completeExceptionally(new RedisTimeoutException(
"Unable to acquire subscription lock after " + time + "ms. " +
"Try to increase 'subscriptionsPerConnection' and/or 'subscriptionConnectionPoolSize' parameters."))) {
subscribeFuture.whenComplete((res, ex) -> {
if (ex == null) {
// 取消订阅
unsubscribe(res, threadId);
}
});
}
acquireFailed(waitTime, unit, threadId);
return false;
} catch (ExecutionException e) {
acquireFailed(waitTime, unit, threadId);
return false;
}
// 接收到通知
try {
// 再次计算尝试获取锁的最大等待时间
time -= System.currentTimeMillis() - current;
if (time <= 0) {
acquireFailed(waitTime, unit, threadId);
return false;
}
// 循环尝试获取锁
while (true) {
long currentTime = System.currentTimeMillis();
// 进行第一次尝试
ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
// lock acquired
if (ttl == null) {
return true;
}
// 剩余剩余等待时间 = 最大等待时间减去尝试获取锁过程消耗的时间
time -= System.currentTimeMillis() - currentTime;
if (time <= 0) {
// 最大剩余等待时间小于0 获取锁失败
acquireFailed(waitTime, unit, threadId);
return false;
}
// waiting for message
currentTime = System.currentTimeMillis();
// 判断 ttl(锁的剩余有效期)和 最大剩余时间的关系。
if (ttl >= 0 && ttl < time) {
// ttl < time 尝试获取信号量的最大时间为ttl
commandExecutor.getNow(subscribeFuture).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} else {
commandExecutor.getNow(subscribeFuture).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
}
// 再次计算尝试获取锁的最大等待时间
time -= System.currentTimeMillis() - currentTime;
if (time <= 0) {
acquireFailed(waitTime, unit, threadId);
return false;
}
// 还有时间则回到上面继续尝试
}
} finally {
unsubscribe(commandExecutor.getNow(subscribeFuture), threadId);
}
// return get(tryLockAsync(waitTime, leaseTime, unit));
}
Redisson 分布锁 tryLock()锁重试机制源码分析
于 2023-10-16 00:05:26 首次发布