Redisson 源码初探(五)获取锁超时 以及 锁超时自动释放
获取锁超自动发现,方法有所改变,不再是使用lock.lock(),而是使用lock.tryLock()public static void main(String[] args) throws Exception {//构建一个配置信息对象Config config = new Config();config.useClusterServers()//定时扫描连接信息 默认1000ms.
·
获取锁超自动发现,方法有所改变,不再是使用lock.lock(),而是使用lock.tryLock()
public static void main(String[] args) throws Exception {
//构建一个配置信息对象
Config config = new Config();
config.useClusterServers()
//定时扫描连接信息 默认1000ms
.setScanInterval(2000)
.addNodeAddress("redis://127.0.0.1:7001");
//因为Redisson 是基于redis封装的一套便于复杂操作的框架
//所以这里构建对象肯定是创建一些与redis的连接
RedissonClient redisson = Redisson.create(config);
//这里是重点 获取锁,这也是重点分析的地方
RLock lock = redisson.getLock("lock");
//尝试获取锁,会等待100S,如果超过了等待时间就会返回false
//如果获取到了锁,那么最多持有10S,超过10S会释放锁
boolean result = lock.tryLock(100, 10, TimeUnit.SECONDS);
//释放锁
lock.unlock();
}
@Override
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
long time = unit.toMillis(waitTime);
long current = System.currentTimeMillis();
final long threadId = Thread.currentThread().getId();
//首先进来就尝试获取锁,跟之前的lock.lock()方法逻辑一样,调用lua脚本,尝试获取锁
//或者是重入锁,将锁对应的map 中的唯一标志 value + 1
//其实不一样的再后面的代码
//
Long ttl = tryAcquire(leaseTime, unit, threadId);
// lock acquired
if (ttl == null) {
return true;
}
//减去尝试获取锁的时间
//假设尝试获取锁 花费了1S,那么time -= 1 ,就是 99S
time -= (System.currentTimeMillis() - current);
//如果超时了就标记尝试获取锁失败
//失败了要干嘛?肯定要将一些环节数据 清除
if (time <= 0) {
acquireFailed(threadId);
return false;
}
current = System.currentTimeMillis();
final RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
if (!await(subscribeFuture, time, TimeUnit.MILLISECONDS)) {
if (!subscribeFuture.cancel(false)) {
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
if (subscribeFuture.isSuccess()) {
unsubscribe(subscribeFuture, threadId);
}
}
});
}
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);
// lock acquired
if (ttl == null) {
return true;
}
time -= (System.currentTimeMillis() - currentTime);
if (time <= 0) {
acquireFailed(threadId);
return false;
}
// waiting for message
currentTime = System.currentTimeMillis();
if (ttl >= 0 && ttl < time) {
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, threadId);
}
// return get(tryLockAsync(waitTime, leaseTime, unit));
}
超时锁的自动释放,其实就是我们自己设置的leaseTime
private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {
//指定了leaseTime 就会走这块代码
if (leaseTime != -1) {
//直接执行lua脚本
//然后不会给RFuture 添加一个监听器,开启一个定时的去刷新过期时间的任务
//意思就是我们设置的过期时间就是一次性的,不会去尝试延长时间
return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
}
RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
return;
}
Long ttlRemaining = future.getNow();
// lock acquired
if (ttlRemaining == null) {
scheduleExpirationRenewal(threadId);
}
}
});
return ttlRemainingFuture;
}
其实看了源码,超时怎么释放?其实依靠的还是redis 本身自身的机制,过期时间,只是这里我们如果自己设置了leaseTime,那么我们Redisson Client 就不会去尝试开启定时任务,每隔一段时间去刷新lock的过期时间。其实和lock.lock()的区别大致就在这一小块
更多推荐
已为社区贡献2条内容
所有评论(0)