redisson分布式锁关键源码
/**
* Redisson分布式锁核心接口,继承了Java的Lock接口
* 提供了分布式环境下的锁操作,支持可重入、过期自动释放等特性
*/
public interface RLock extends Lock, RExpirable, RLockAsync {
/**
* 尝试获取锁,获取成功后锁会在指定时间后自动释放
*
* @param waitTime 最多等待时间
* @param leaseTime 锁自动释放时间
* @param unit 时间单位
* @return 如果获取锁成功返回true,否则返回false
* @throws InterruptedException 如果线程被中断则抛出异常
*/
boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;
/**
* 强制释放锁,不管当前锁是否被当前线程持有
* 注意:此方法可能会释放其他线程持有的锁,使用时需谨慎
*/
void forceUnlock();
/**
* 检查当前锁是否被任何线程持有
*
* @return 如果锁被持有则返回true,否则返回false
*/
boolean isLocked();
/**
* 检查当前锁是否被当前线程持有
*
* @return 如果当前线程持有锁则返回true,否则返回false
*/
boolean isHeldByCurrentThread();
/**
* 获取当前线程持有锁的次数(重入次数)
*
* @return 锁的重入次数
*/
int getHoldCount();
/**
* 尝试获取锁,在指定时间内如果获取到锁,会保持指定的租约时间
* 如果租约时间到了还未释放,锁会自动释放
*
* @param leaseTime 锁的租约时间
* @param unit 时间单位
* @return 如果获取锁成功返回true
* @throws InterruptedException 如果线程被中断则抛出异常
*/
boolean tryLock(long leaseTime, TimeUnit unit) throws InterruptedException;
/**
* 加锁,并且指定锁的自动释放时间
*
* @param leaseTime 锁自动释放时间
* @param unit 时间单位
*/
void lock(long leaseTime, TimeUnit unit);
}
/**
* Redisson分布式锁的默认实现类
*/
public class RedissonLock extends RedissonExpirable implements RLock {
/**
* 加锁操作,默认锁不会自动释放,需要手动调用unlock()
* 内部通过Lua脚本保证加锁操作的原子性
*/
@Override
public void lock() {
try {
// 调用tryLock方法,等待时间为-1表示一直等待,租约时间为-1表示不自动释放
lock(-1, null, false);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
/**
* 带超时时间的加锁操作
*
* @param leaseTime 锁自动释放时间
* @param unit 时间单位
*/
@Override
public void lock(long leaseTime, TimeUnit unit) {
try {
lock(leaseTime, unit, false);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
/**
* 尝试获取锁的核心实现
*
* @param waitTime 最多等待时间
* @param leaseTime 锁自动释放时间
* @param unit 时间单位
* @return 是否获取锁成功
* @throws InterruptedException 如果线程被中断则抛出异常
*/
@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();
// 尝试获取锁
Long ttl = tryAcquire(leaseTime, unit, threadId);
// 如果ttl为null,表示获取锁成功
if (ttl == null) {
return true;
}
// 如果剩余等待时间小于等于0,返回获取失败
time -= System.currentTimeMillis() - current;
if (time <= 0) {
acquireFailed(threadId);
return false;
}
current = System.currentTimeMillis();
// 订阅锁释放事件,当锁释放时会收到通知
RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
// 等待订阅完成,或者超时
if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {
// 如果订阅超时,取消订阅并返回失败
if (!subscribeFuture.cancel(false)) {
subscribeFuture.onComplete((res, e) -> {
if (e == null) {
unsubscribe(subscribeFuture.getNow(), threadId);
}
}, Thread.currentThread().getThreadGroup());
}
acquireFailed(threadId);
return false;
}
try {
// 再次计算剩余等待时间
time -= System.currentTimeMillis() - current;
if (time <= 0) {
acquireFailed(threadId);
return false;
}
// 循环等待获取锁
while (true) {
long currentTime = System.currentTimeMillis();
// 再次尝试获取锁
ttl = tryAcquire(leaseTime, unit, threadId);
// 成功获取锁
if (ttl == null) {
return true;
}
// 计算还能等待的时间
time -= System.currentTimeMillis() - currentTime;
if (time <= 0) {
acquireFailed(threadId);
return false;
}
// 等待锁释放通知或者超时
currentTime = System.currentTimeMillis();
if (ttl >= 0 && ttl < time) {
// 如果锁的剩余存活时间小于等待时间,则等待ttl时间
getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} else {
// 否则等待剩余的等待时间
getEntry(threadId).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
}
// 再次计算剩余等待时间
time -= System.currentTimeMillis() - currentTime;
if (time <= 0) {
acquireFailed(threadId);
return false;
}
}
} finally {
// 取消订阅
unsubscribe(subscribeFuture.getNow(), threadId);
}
}
/**
* 释放锁操作
* 内部通过Lua脚本保证释放锁的原子性,防止误释放其他线程的锁
*/
@Override
public void unlock() {
try {
get(unlockAsync(Thread.currentThread().getId()));
} catch (RedisException e) {
if (e.getCause() instanceof IllegalMonitorStateException) {
throw (IllegalMonitorStateException) e.getCause();
} else {
throw e;
}
}
}
/**
* 尝试获取锁的具体实现
*
* @param leaseTime 租约时间
* @param unit 时间单位
* @param threadId 当前线程ID
* @return 锁的剩余存活时间,如果为null表示获取成功
*/
private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
return get(tryAcquireAsync(leaseTime, unit, threadId));
}
/**
* 异步尝试获取锁
*
* @param leaseTime 租约时间
* @param unit 时间单位
* @param threadId 当前线程ID
* @return 异步结果,包含锁的剩余存活时间,如果为null表示获取成功
*/
private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
// 如果指定了租约时间,直接尝试获取锁
if (leaseTime != -1) {
return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
}
// 如果没有指定租约时间,使用默认的30秒,并启动定时任务自动续期
RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(),
TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
if (e != null) {
return;
}
// 成功获取锁,启动看门狗定时续期
if (ttlRemaining == null) {
scheduleExpirationRenewal(threadId);
}
});
return ttlRemainingFuture;
}
/**
* 执行Lua脚本获取锁的核心逻辑
* Lua脚本保证了操作的原子性
*/
private <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
// Lua脚本:
// 1. 如果锁不存在,则设置锁并设置过期时间
// 2. 如果锁存在且是当前线程持有,则增加重入次数并重置过期时间
// 3. 否则返回锁的剩余存活时间
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);",
Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
/**
* 定时任务,用于自动续期锁的过期时间
* 防止在持有锁期间锁过期被自动释放
*
* @param threadId 线程ID
*/
private void scheduleExpirationRenewal(long threadId) {
ExpirationEntry entry = new ExpirationEntry();
ExpirationEntry oldEntry = EXPIRATION_RENEWAL_MAP.putIfAbsent(getEntryName(), entry);
if (oldEntry != null) {
oldEntry.addThreadId(threadId);
return;
}
// 启动定时任务,每隔internalLockLeaseTime / 3时间续期一次
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
// 执行续期操作
RFuture<Boolean> future = renewExpirationAsync(threadId);
future.onComplete((res, e) -> {
EXPIRATION_RENEWAL_MAP.remove(getEntryName());
if (e != null) {
log.error("Can't update lock " + getName() + " expiration", e);
return;
}
// 如果续期成功,继续定时续期
if (res) {
scheduleExpirationRenewal(threadId);
}
});
}
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
entry.setTimeout(task);
}
}
本文来自博客园,作者:诸葛匹夫,转载请注明原文链接:https://www.cnblogs.com/shenxingzhuge/p/19070769
卡里离冰冷的40个亿还差39多个亿
浙公网安备 33010602011771号