@Override
public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
long threadId = Thread.currentThread().getId();
// 核心加锁流程
Long ttl = tryAcquire(leaseTime, unit, threadId);
// 加锁成功 返回
if (ttl == null) {
return;
}
// 订阅解锁消息
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);
}
// get(lockAsync(leaseTime, unit));
}
private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {
if (leaseTime != -1) {
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();
// 加锁成功,创建定时刷新锁超时时间任务
if (ttlRemaining == null) {
scheduleExpirationRenewal(threadId);
}
}
});
return ttlRemainingFuture;
}
<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return evalWriteAsync(getName(), LongCodec.INSTANCE, command,
"if (redis.call('exists', KEYS[1]) == 0) then " + // 判断key是否已经存在,如果不存在则直接加锁操作
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " + // 给key的value自增1(核心加锁原理)
"redis.call('pexpire', KEYS[1], ARGV[1]); " + // 设置锁超时时间
"return nil; " + // 加锁成功返回null
"end; " +
// 加锁的key存在,判断该key存储的value是否是当前请求加锁的线程id,如果是,执行锁重入的操作
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " + // value自增1
"redis.call('pexpire', KEYS[1], ARGV[1]); " + // 刷新过期时间
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);", // 加锁失败,返回锁的过期时间
Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
private void scheduleExpirationRenewal(final long threadId) {
if (expirationRenewalMap.containsKey(getEntryName())) {
return;
}
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
// 判断当前线程的这把锁是否存在,如果存在的话,则刷新锁过期时间
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return 1; " +
"end; " +
"return 0;",
Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
future.addListener(new FutureListener<Boolean>() {
@Override
public void operationComplete(Future<Boolean> future) throws Exception {
expirationRenewalMap.remove(getEntryName());
if (!future.isSuccess()) {
log.error("Can't update lock " + getName() + " expiration", future.cause());
return;
}
if (future.getNow()) {
// reschedule itself
scheduleExpirationRenewal(threadId);
}
}
});
}
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);// 定时任务何时执行 ? 锁超时时间 / 3 (看门狗核心)
if (expirationRenewalMap.putIfAbsent(getEntryName(), task) != null) {
task.cancel();
}
}
@Override
public void unlock() {
Boolean opStatus = get(unlockInnerAsync(Thread.currentThread().getId()));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
if (opStatus) {
// 取消定时刷新锁超时任务(看门狗)
cancelExpirationRenewal();
}
// Future future = unlockAsync();
// future.awaitUninterruptibly();
// if (future.isSuccess()) {
// return;
// }
// if (future.cause() instanceof IllegalMonitorStateException) {
// throw (IllegalMonitorStateException)future.cause();
// }
// throw commandExecutor.convertException(future);
}
核心解锁代码
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
// 判断锁是否存在,如果不存在,则发布一条解锁的消息 --> 返回1
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end;" +
// 判断当前线程加的这把锁是否存在(value 是否 = getLockName(threadId)),不存在则直接返回null
"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
"return nil;" +
"end; " +
// // 加锁的时候+1 ,这边解锁需要减一
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
// 判断减一以后是否还是>0,如果是则代表存在锁重入 --> 刷新锁超时时间 --> 返回 0
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
// 否则,执行删除锁操作,并且发布一条解锁的消息 --> 返回1
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; "+
"end; " +
"return nil;",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));
}
我们可以看到,在前面加锁的时候其实已经subscribe了这个channel,所以这边解锁publish了这个解锁的消息,之前创建的监听任务就可以监听到这个解锁消息 「这里就不对这块流程说明了,无非是发布订阅的机制,我们核心是要掌握一整个加锁/解锁,阻塞/唤醒的机制」
接下来我们来看看,监听到消息后的处理
@Override
protected void onMessage(RedissonLockEntry value, Long message) {
// 判断订阅到消息是否是解锁消息
if (message.equals(unlockMessage)) {
// 唤醒之前加锁失败阻塞在第同步队列的的线程
value.getLatch().release();
while (true) {
Runnable runnableToExecute = null;
synchronized (value) {
Runnable runnable = value.getListeners().poll();
if (runnable != null) {
if (value.getLatch().tryAcquire()) {
runnableToExecute = runnable;
} else {
value.addListener(runnable);
}
}
}
if (runnableToExecute != null) {
runnableToExecute.run();
} else {
return;
}
}
}
}
}