1.原理图
2.获取锁的方法
//获取锁 void lock();
//获取锁,并设置锁过期时间 void lock(long leaseTime, TimeUnit unit);
//尝试获取锁,成功返回true boolean tryLock();
//尝试获取锁,成功返回true,waitTime等待时间,leaseTime释放锁时间默认为-1 boolean tryLock(long time, TimeUnit unit) throws InterruptedException
//参照上 boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;
//获取锁 public void lock(long leaseTime, TimeUnit unit) { try { lockInterruptibly(leaseTime, unit); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
//lock相关方法实际执行的方法
public void lockInterruptibly(long leaseTime, TimeUnit unit)throws InterruptedException{
//当前线程id
long threadId = Thread.currentThread().getId();
//执行lua脚本获取锁,ttl返回的的是返回锁的过期时间(只有锁没获取成功才会返回过期时间)
Long ttl = tryAcquire(leaseTime, unit, threadId);
// lock acquired
if (ttl == null) {
return;
}
//如果获取锁失败,则订阅到对应这个锁的channel,但其他线程释放锁时,通知线程去获取锁
RFuture<RedissonLockEntry> future = subscribe(threadId);
/
commandExecutor.syncSubscription(future);
try {
//死循环尝试获取锁
while (true) {
ttl = tryAcquire(leaseTime, unit, threadId);
// lock acquired
if (ttl == null) {
break;
}
// waiting for message
if (ttl >= 0) {
getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} else {
getEntry(threadId).getLatch().acquire();
}
}
} finally {
//取消订阅
unsubscribe(future, threadId);
}
}
//获取锁方法,
private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
//get方法实际是线程池执行,返回锁失效时间
return get(tryAcquireAsync(leaseTime, unit, threadId));
}
//
private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
if (leaseTime != -1) {
//执行lua脚本获取锁
return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
}
//getLockWatchdogTimeout 默认时间30s释放锁
RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
if (e != null) {
return;
}
// lock acquired
if (ttlRemaining == null) {
定时任务不断续锁(看门狗)
scheduleExpirationRenewal(threadId);
}
});
return ttlRemainingFuture;
}
//获取锁,可重入锁,返回锁过期时间
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
//==0表示key不存在,无线程获取锁
"if (redis.call('exists', KEYS[1]) == 0) then " +
如果不存在,则设置key的 某个字段 value=1
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
设置key过期时间
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
//hexists等于1表示存在
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
//设置key的 某个字段加1
"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.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
//getName()我们定义锁的key,internalLockLeaseTime释放时间,
//getLockName(threadId)为id + ":" + threadId,id为uuId
}