Redisson 分布式锁源码 10:读写锁

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,倚天版 1GB 1个月
简介: Redisson 还支持可重入读写锁,允许在分布式场景下,同时有多个读锁和一个写锁处于加锁状态。

前言


Redisson 还支持可重入读写锁,允许在分布式场景下,同时有多个读锁和一个写锁处于加锁状态。


使用读写锁

Redisson 读写锁实现了 JUC 下的 ReadWriteLock,使用方式基本相同。

网络异常,图片无法展示
|


源码

加锁源码基本和之前的可重入锁加锁无区别,唯一的差异就是在 Lua 脚本这里。

所以下面着重分析 Lua 脚本。


读锁源码

源码地址:org.redisson.RedissonReadLock#tryLockInnerAsync

参数列表:

  1. KEYS[1]:锁名字 anyRWLock
  2. KEYS[2]:锁超时 key {锁名字}:UUID:ThreadId:rwlock_timeout 组成的字符串,{anyRWLock}:e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1:rwlock_timeout
  3. ARGV[1]:锁时间,默认 30s
  4. ARGV[2]:当前线程,UUID:ThreadId 组成的字符串,e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1
  5. ARGV[3]:写锁名字,getWriteLockName(threadId) 写锁名字,UUID:ThreadId:write 组成的字符串, e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1:write

网络异常,图片无法展示
|


首次加读锁

网络异常,图片无法展示
|

  1. 锁不存在,直接走第一部分
  2. 设置锁 anyRWLock 的 mode 是 read,表示这是个读锁
  3. 设置锁 anyRWLock 的 e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1(当前线程)值为 1
  4. 设置锁 {anyRWLock}:e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1:rwlock_timeout:1 的值是 1,表示当前线程,当前重入的超时时间
  5. 设置两个 RedisKey 的过期时间


读锁重入

网络异常,图片无法展示
|

如果是重入的情况下:

  1. 锁存在,且是读锁,直接进入第二部分
  2. 对锁 anyRWLock 的 e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1(当前线程)值自增 1 表是重入
  3. 再创建 {anyRWLock}:e70b1307-9ddd-43de-ac9d-9c42b5c99a0d:1:rwlock_timeout:2 表示第二次加锁的超时时间


读读支持

网络异常,图片无法展示
|

  1. 锁存在,进入第二部分
  2. 对当前线程的值自增 1,这里已经是第二个线程了
  3. 设置第二个线程 {anyRWLock}:7c390320-78e3-497f-a3d8-ac34a44d0464:48:rwlock_timeout:1 的超时时间


写读互斥

已经加了读锁了,此时写锁进来,不满足第一部分,也不满足第二部分,所以直接返回当前锁的剩余时间。

然后再 Java 代码中进行 while (true) 自旋等待。

通过上面可以看出,在读锁的时候:

  1. 锁 anyRWLock 是哈希表结构的
  2. 加锁时,会对哈希表设置 mode 字段来表示这个锁是读锁还是写锁,mode = read 表示读锁
  3. 加锁时,会对哈希表设置当前线程 anyRWLock 的 UUID:ThreadId 字段,值表示重入次数
  4. 每次加锁,会额外维护一个 key 表示这次锁的超时时间,这个 key 的结构是 {锁名字}:UUID:ThreadId:rwlock_timeout:重入次数


写锁源码

源码地址:org.redisson.RedissonWriteLock#tryLockInnerAsync

参数列表:

  1. KEYS[1]:当前锁 anyRWLock
  2. ARGV[1]:锁时间,默认 30s
  3. ARGV[2]:写锁名字,UUID:ThreadId:write 组成的字符串,c69a9ed4-5c30-4952-814e-c0b94ad03a7f:1:write

网络异常,图片无法展示
|

写锁源码相对比较好理解:

  1. 判断锁的模式,是写锁
  2. 锁不存在直接创建
  3. 锁存在,再判断是不是自己,是自己则重入

网络异常,图片无法展示
|

这么下来,可以看出直接满足,写写互斥,读写互斥,当前线程又可以重入。


总结


到这里基本上读写锁就看完了,读锁实现的稍微复杂一些,写锁简单明了。

在读锁的时候:

  1. 锁 anyRWLock 是哈希表结构
  2. 加锁时,会对哈希表设置 mode 字段来表示这个锁是读锁还是写锁,mode = read 表示读锁
  3. 加锁时,会对哈希表设置当前线程 anyRWLock 的 UUID:ThreadId 字段,值表示重入次数
  4. 每次加锁,会额外维护一个 key 表示这次锁的超时时间,这个 key 的结构是 {锁名字}:UUID:ThreadId:rwlock_timeout:重入次数

在写锁的时候:

  1. 锁 anyRWLock 是哈希表结构
  2. 加锁时,会对哈希表设置 mode 字段来表示这个锁是读锁还是写锁,mode = write 表示写锁
  3. 在 anyRWLock 中再额外维护一个字段 UUID:ThreadId:write 表示重入次数

至于看门狗,这些都和之前的一样,就不额外介绍了。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
26天前
|
存储 缓存 NoSQL
Redis常见面试题(二):redis分布式锁、redisson、主从一致性、Redlock红锁;Redis集群、主从复制,哨兵模式,分片集群;Redis为什么这么快,I/O多路复用模型
redis分布式锁、redisson、可重入、主从一致性、WatchDog、Redlock红锁、zookeeper;Redis集群、主从复制,全量同步、增量同步;哨兵,分片集群,Redis为什么这么快,I/O多路复用模型——用户空间和内核空间、阻塞IO、非阻塞IO、IO多路复用,Redis网络模型
Redis常见面试题(二):redis分布式锁、redisson、主从一致性、Redlock红锁;Redis集群、主从复制,哨兵模式,分片集群;Redis为什么这么快,I/O多路复用模型
|
2月前
|
NoSQL Redis
redis分布式锁redisson
底层会尝试去加锁,如果加锁失败,会睡眠,自旋加锁,直到获取到锁为止。
39 1
|
2月前
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
159 0
|
3月前
|
关系型数据库 分布式数据库 数据库
【PolarDB开源】PolarDB-X源码解读:分布式事务处理机制揭秘
【5月更文挑战第20天】PolarDB-X,PolarDB家族的一员,专注于大规模分布式事务处理,采用2PC协议保证ACID特性。源码解析揭示其通过预提交、一致性快照隔离和乐观锁优化事务性能,以及利用事务日志进行故障恢复。深入理解其事务处理机制对开发者掌握分布式数据库核心技术至关重要。随着开源社区的发展,更多优化方案将涌现,助力构建更强大的分布式数据库系统。
156 6
|
1天前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
|
4天前
|
算法
分布式锁设计问题之重建节点锁信息时要分为多个阶段如何解决
分布式锁设计问题之重建节点锁信息时要分为多个阶段如何解决
|
4天前
分布式锁设计问题之节点A向节点C发起对R1的加锁请求如何解决
分布式锁设计问题之节点A向节点C发起对R1的加锁请求如何解决
|
30天前
|
负载均衡 NoSQL Java
|
12天前
|
NoSQL Go API
[go 面试] 为并发加锁:保障数据一致性(分布式锁)
[go 面试] 为并发加锁:保障数据一致性(分布式锁)
|
1月前
|
关系型数据库 分布式数据库 数据库
PolarDB-X源码解析:揭秘分布式事务处理
【7月更文挑战第3天】**PolarDB-X源码解析:揭秘分布式事务处理** PolarDB-X,应对大规模分布式事务挑战,基于2PC协议确保ACID特性。通过预提交和提交阶段保证原子性与一致性,使用一致性快照隔离和乐观锁减少冲突,结合故障恢复机制确保高可用。源码中的事务管理逻辑展现了优化的分布式事务处理流程,为开发者提供了洞察分布式数据库核心技术的窗口。随着开源社区的发展,更多创新实践将促进数据库技术进步。
44 3

热门文章

最新文章