ttl 这段的获取逻辑 , 翻译翻译就是,如果前面有人排队,就以前面的超时时间为准,如果没人排队 , 就拿锁的超时时间 。获取到 ttl,就对添加到线程集合和时间集合 。
以上就是公平锁的加锁 lua 脚本的全部逻辑 。讲的有点乱,但是只要能搞清楚keys1、2、3对应着哪种数据类型 , 理解整个逻辑应该问题不大 。
解锁解锁的核心 lua 脚本是下面这段RedissonFairLock#unlockInnerAsync
protected RFuture<Boolean> unlockInnerAsync(long threadId) {return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,// remove stale threads"while true do "// 线程队列为空,证明没有人排队,退出循环+ "local firstThreadId2 = redis.call('lindex', KEYS[2], 0);"+ "if firstThreadId2 == false then "+ "break;"+ "end; "// 能到这里,证明有人排队 , 拿出在排队的第一个人的超时时间,如果超时了,则移除相应数据+ "local timeout = tonumber(redis.call('zscore', KEYS[3], firstThreadId2));"+ "if timeout <= tonumber(ARGV[4]) then "+ "redis.call('zrem', KEYS[3], firstThreadId2); "+ "redis.call('lpop', KEYS[2]); "+ "else "+ "break;"+ "end; "+ "end;"// 如果锁不存在,则通过订阅发布机制通知下一个等待中的线程+ "if (redis.call('exists', KEYS[1]) == 0) then " +"local nextThreadId = redis.call('lindex', KEYS[2], 0); " +"if nextThreadId ~= false then " +"redis.call('publish', KEYS[4] .. ':' .. nextThreadId, ARGV[1]); " +"end; " +"return 1; " +"end;" +// 如果当前线程已经不存在锁里面,直接返回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); " +"if (counter > 0) then " +// 锁次数仍然大于0,则刷新锁的存活时间"redis.call('pexpire', KEYS[1], ARGV[2]); " +"return 0; " +"end; " +// 删除锁"redis.call('del', KEYS[1]); " +// 订阅发布机制通知下一个等待中的线程"local nextThreadId = redis.call('lindex', KEYS[2], 0); " +"if nextThreadId ~= false then " +"redis.call('publish', KEYS[4] .. ':' .. nextThreadId, ARGV[1]); " +"end; " +"return 1; ",Arrays.asList(getRawName(), threadsQueueName, timeoutSetName, getChannelName()),LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId), System.currentTimeMillis());}
算了,不想写了,看注释吧 。
总结本文介绍了Redisson的公平锁,逻辑大体上和普通可重入锁一致,核心在于 lua 脚本 , 运用了Redis的3种数据类型 。
推荐阅读
- OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境
- Redisson源码解读-分布式锁
- 源码级深度理解 Java SPI
- Dubbo-聊聊通信模块设计
- 【lwip】10-ICMP协议&源码分析
- 【lwip】09-IPv4协议&超全源码实现分析
- 京东云开发者|经典同态加密算法Paillier解读 - 原理、实现和应用
- 从BeanFactory源码看Bean的生命周期
- 详解AQS中的condition源码原理