读写锁得概念我们就不再赘述了
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);
ReadWriteLock readWriteLock = redisson.getReadWriteLock("lock");
readWriteLock.readLock().lock();
readWriteLock.writeLock().lock();
//释放锁
readWriteLock.readLock().unlock();
readWriteLock.writeLock().unlock();
}
我们先来看看读锁,RedissonReadLock ,其实我们大概现在都知道了,加锁得逻辑最主要还是去理解lua脚本,RedissonReadLock 覆盖了一些主要得方法,我们主要研究 加锁 释放锁 以及renew续约的lua脚本
我们直接来看RedissonReadLock 加锁的lua脚本
还是研究参数代表的意义
KEY[1] = 锁的名称
KEY[2] = getReadWriteTimeoutNamePrefix(threadId) {lockName};UUID_01:ThreadId_01 : rwlock_timeout
ARGV[1] = internalLockLeaseTime
ARGV[2] = getLockName(threadId) UUID_01:threadId
ARGV[3] = getWriteLockName(threadId) UUID_01:ThreadId:write
读锁的lua脚本
最简单的加锁逻辑是非常的清晰的,但是我们肯定是要分析复杂的逻辑对吧,比如可重入性
(1)连续加2次读锁
(2)连续加2次写锁
(3)先读锁,后写锁
(4)先写锁,后读锁
这几种情况是如何运转的? 也就是研究锁的可重入性
@Override
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
//hget key mode 就是代表从key对应的map数据结构中获取mode对应的值
"local mode = redis.call('hget', KEYS[1], 'mode'); " +
"if (mode == false) then " +
//设置模式为读模式
"redis.call('hset', KEYS[1], 'mode', 'read'); " +
//设置读锁持有的线程名称
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
//两个点是什么意思? 就是字符串拼接,将KEY[2]:1 生成新的字符串
"redis.call('set', KEYS[2] .. ':1', 1); " +
//设置KEY[1] KEY[2]的过期时间
"redis.call('pexpire', KEYS[2] .. ':1', ARGV[1]); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
//锁的可重入性逻辑脚本 ,不管之前是读还是写都将其 +1
"if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then " +
//将对应的值 +1
"local ind = redis.call('hincrby', KEYS[1], ARGV[2], 1); " + //设置 该次加锁对应timeout key