基于Redisson的分布式锁
该方法实现了一个基于Redisson的分布式锁获取逻辑,支持可中断和不可中断的锁等待。功能如下:
- 尝试获取锁 :通过
tryAcquire
尝试加锁,失败则返回剩余生存时间(TTL)。 - 订阅锁释放事件:若未获取锁,则订阅锁释放通知,进入等待。
- 循环重试获取锁:在锁被持有期间持续重试,根据TTL等待或阻塞直到锁释放。
以下是对这段代码的逐行详细注释
java
private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
// 获取当前线程的 ID,用于标识锁的持有者
long threadId = Thread.currentThread().getId();
// 尝试获取锁,并返回锁的剩余生存时间(TTL)。
// 如果返回 null,表示成功获取锁;否则需要进入等待逻辑。
Long ttl = this.tryAcquire(leaseTime, unit, threadId);
// 如果 ttl 不为 null,说明锁已被其他线程持有,需要订阅锁释放事件并等待
if (ttl != null) {
// 订阅锁释放通知,返回一个 Future 对象,用于监听锁是否被释放
RFuture<RedissonLockEntry> future = this.subscribe(threadId);
// 根据 interruptibly 参数决定使用可中断还是不可中断的同步方式
if (interruptibly) {
// 可中断的方式同步订阅,允许在等待过程中响应中断
this.commandExecutor.syncSubscriptionInterrupted(future);
} else {
// 不可中断的方式同步订阅
this.commandExecutor.syncSubscription(future);
}
try {
// 进入自旋循环,持续尝试获取锁直到成功或超时
while(true) {
// 再次尝试获取锁,判断是否已释放
ttl = this.tryAcquire(leaseTime, unit, threadId);
// 如果 ttl 为 null,说明成功获取锁,退出循环
if (ttl == null) {
return;
}
// 如果 TTL 大于等于 0,说明锁还有剩余时间,等待指定的时间
if (ttl >= 0L) {
try {
// 使用信号量(latch)等待指定时间,尝试获取锁
((RedissonLockEntry)future.getNow()).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} catch (InterruptedException var13) {
// 捕获中断异常,如果 interruptibly 为 true,则重新抛出
InterruptedException e = var13;
if (interruptibly) {
throw e;
}
// 如果 interruptibly 为 false,则继续等待
((RedissonLockEntry)future.getNow()).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
}
}
// 如果 TTL 小于 0,说明没有设置超时时间,直接阻塞等待锁释放
else if (interruptibly) {
// 可中断方式阻塞等待
((RedissonLockEntry)future.getNow()).getLatch().acquire();
} else {
// 不可中断方式阻塞等待
((RedissonLockEntry)future.getNow()).getLatch().acquireUninterruptibly();
}
}
} finally {
// 取消订阅,释放资源,避免内存泄漏
this.unsubscribe(future, threadId);
}
}
}
✅ 总结
tryAcquire(...)
:尝试获取锁,失败则返回锁的剩余生存时间(TTL)。subscribe(...)
:订阅锁释放事件,以便在锁释放时收到通知。syncSubscription(...)
/syncSubscriptionInterrupted(...)
:根据是否支持中断选择不同的订阅策略。- 自旋 + latch 等待机制:通过不断重试和信号量控制,确保线程在锁释放后能及时获取。
unsubscribe(...)
:确保资源释放,避免内存泄漏。
🔧 推荐优化建议(可选)
如果你希望提高系统的健壮性和灵活性,可以考虑使用 tryLock(...)
方法并设置合理的超时时间,以避免长时间阻塞。例如:
java
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
// 执行关键业务逻辑
} finally {
lock.unlock();
}
} else {
log.warn("未能获取到锁,跳过本次执行");
}
这种方式更适合对响应时间有要求的场景。