Redission实现的分布式锁的可重入性

news/2025/7/8 15:26:47

Redisson 分布式锁在 Redis 中存储可重入状态所使用的 Hash 结构,并通过示例说明。

核心数据结构

  • Key: 锁的名称。例如:"myLock"
  • 数据类型: Hash (Redis HSET / HGET / HINCRBY 操作的对象)。
  • Hash Field (字段名): 客户端唯一标识符。格式通常为:UUID:threadId
    • UUID: 生成 Redisson 客户端实例时创建的一个全局唯一 ID(一个 JVM 进程一个)。
    • threadId: 当前请求锁的线程 ID(Java 中的 Thread.currentThread().getId())。
    • 作用: 精确标识是哪个 JVM 进程中的哪个线程持有锁。这是实现可重入的基础,同一个线程多次获取锁时,Field 相同。
  • Hash Value (字段值): 一个整数,表示该线程对这把锁的 重入次数
    • 当线程第一次成功获取锁时,这个值被设置为 1
    • 当同一个线程再次成功获取锁(重入)时,这个值会递增(+1)。
    • 当线程释放锁时,这个值会递减(-1)。
    • 只有当这个值减到 0 时,才表示该线程已经完全释放了这把锁,此时 Redis 会删除这个 Hash Key。

示例场景

假设:

  1. 锁名称 (Key): "order_lock:1001" (假设为处理订单 ID 1001 的锁)
  2. 客户端 A 的 UUID: "550e8400-e29b-41d4-a716-446655440000"
  3. 客户端 A 中线程 ID: 31
场景 1: 线程 31 第一次获取锁成功
  • Redis 命令模拟 (Lua 脚本执行后的效果):
    HSET order_lock:1001 550e8400-e29b-41d4-a716-446655440000:31 1
    PEXPIRE order_lock:1001 30000 # 设置 30 秒过期时间
    
  • Redis 中存储的数据:
    Key: "order_lock:1001"Type: hashField: "550e8400-e29b-41d4-a716-446655440000:31" -> Value: 1 (整数)TTL: ~30000ms
    
  • 解释: 线程 31 首次获取锁,重入次数为 1
场景 2: 同一个线程 31 在锁内再次获取锁成功 (重入)
  • 假设线程 31 在持有 order_lock:1001 的代码块内,又调用了另一个需要获取同一把锁的方法。
  • Redis 命令模拟 (Lua 脚本执行后的效果):
    HINCRBY order_lock:1001 550e8400-e29b-41d4-a716-446655440000:31 1 # 值从1变成2
    PEXPIRE order_lock:1001 30000 # 重置过期时间
    
  • Redis 中存储的数据:
    Key: "order_lock:1001"Type: hashField: "550e8400-e29b-41d4-a716-446655440000:31" -> Value: 2 (整数)TTL: ~30000ms (被重置)
    
  • 解释: 同一个线程 31 重入锁,重入次数递增到 2。锁的过期时间被重置(看门狗或续期逻辑)。
场景 3: 线程 31 第一次释放锁 (重入锁)
  • 线程 31 执行到外层锁的 unlock()
  • Redis 命令模拟 (Lua 脚本执行后的效果):
    HINCRBY order_lock:1001 550e8400-e29b-41d4-a716-446655440000:31 -1 # 值从2变成1
    PEXPIRE order_lock:1001 30000 # 重置过期时间 (因为计数 > 0)
    
  • Redis 中存储的数据:
    Key: "order_lock:1001"Type: hashField: "550e8400-e29b-41d4-a716-446655440000:31" -> Value: 1 (整数)TTL: ~30000ms
    
  • 解释: 线程 31 释放了一次锁(对应第一次获取),重入次数减为 1。锁仍然被该线程持有(计数 > 0),所以 Key 没有被删除,并且过期时间被重置。
场景 4: 线程 31 第二次释放锁 (完全释放)
  • 线程 31 执行到内层锁的 unlock()
  • Redis 命令模拟 (Lua 脚本执行后的效果):
    HINCRBY order_lock:1001 550e8400-e29b-41d4-a716-446655440000:31 -1 # 值从1变成0
    DEL order_lock:1001 # 因为计数减到0,删除Key
    PUBLISH redisson_lock__channel:{order_lock:1001} ... # 发布解锁消息通知等待者
    
  • Redis 中存储的数据:
    Key: "order_lock:1001" -> 已被删除
    
  • 解释: 线程 31 释放了最后一次持有的锁(对应第二次获取),重入次数减为 0。此时 Redis 会删除整个 Key order_lock:1001,并通过 PUBLISH 命令通知所有正在等待这把锁的其他客户端。

关键点总结

  1. 结构: 一个锁 Key (String) 对应一个 Hash 数据结构。
  2. 标识: Hash 的 Field<ClientUUID>:<ThreadID>,唯一标识持有锁的客户端和线程。
  3. 计数: Hash 的 Value 是一个 整数,记录该线程对这把锁的 重入次数
  4. 原子操作: 加锁 (HINCRBY ... 1 / HSET ... 1)、解锁 (HINCRBY ... -1)、检查持有者 (HEXISTS)、删除锁 (DEL) 等关键操作都封装在 Lua 脚本中执行,保证原子性。
  5. 可重入性: 同一个线程多次获取锁时,操作的是同一个 Hash Field,对其 Value 进行递增;释放时递减,直到为 0 才真正释放锁。这完美实现了可重入锁的语义。

通过这种 Hash 结构的设计,Redisson 高效、清晰地实现了分布式环境下锁的可重入性管理。


https://dhexx.cn/news/show-5542228.html

相关文章

new()和new[]有什么区别?

new()和new[]有什么区别&#xff1f; 1、new[]的使用较为简单&#xff0c;一般用来开辟内存并初始化&#xff0c;常用于设置动态数组的大小。 int a[]; //声明动态数组 initial begina new[3]; //为动态数组分配3个元素foreach (a[i]) a[i] i; //元素初始化 end2、new…

如何高效实现公司文件管理

要实现公司文件管理的高效&#xff0c;企业应聚焦统一文件规范、部署文档管理系统、强化权限控制、推动协同编辑、实施定期清理、推进文化建设、引入可视化分析。其中&#xff0c;统一文件规范是文件高效管理的基础。若缺乏清晰的命名规则与分类体系&#xff0c;即便配备了先进…

【AI论文】ReasonMed:一个370K的多智能体生成数据集,用于推进医疗推理

摘要&#xff1a;尽管基于推理的大型语言模型&#xff08;LLM&#xff09;在数学和编程方面表现出色&#xff0c;但它们在知识密集型医疗问题回答方面的能力仍未得到充分探索。为解决这一问题&#xff0c;我们推出了ReasonMed&#xff0c;这是最大的医疗推理数据集&#xff0c;…

singlefligt使用方法和源码解读

singlefligt使用方法和源码解读 介绍 sync.once保证其整个生命周期内只调用一次&#xff1b;而singleflight则可以保证在一定范围内其只调用一次。 背景|使用场景 应对缓存击穿&#xff1a;加锁可以解决这个问题&#xff0c;但是加锁不太灵活&#xff08;不能控制访问频率之…

ROS2 笔记汇总(2) 通信接口

在 ROS 系统中&#xff0c;通信接口&#xff08;Interface&#xff09; 是节点之间传递信息的标准“语言协议”&#xff0c;确保了不同功能节点之间可以正确理解和使用彼此传送的数据内容。我们可以将其理解为“数据结构格式定义”&#xff0c;贯穿于话题&#xff08;Topic&…

2025年中总结

1、工作生活 下半年补充下简历直接跳槽&#xff1a; 工作更多的在做一些内部优化的事情&#xff0c;这类工作算是价值偏低的一类工作&#xff0c;跟组长沟通过&#xff0c;反馈为不可能有人一直只做高价值工作&#xff0c;不过在我看了其他的人的工作分配后我就呵呵了。 上半…

反转链表二--LeetCode

题目 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#xff1a;[…

用Go写一个飞书机器人定时发送消息的程序

下面是一个每分钟调用飞书机器人 Webhook 地址发送消息的完整 Go 示例。 ✅ 一、准备工作 你需要一个飞书机器人的 Webhook 地址&#xff0c;形如&#xff1a; https://open.feishu.cn/open-apis/bot/v2/hook/xxxx-xxxx-xxxx-xxxx确保你的机器人在群聊中&#xff0c;并已开启…

uniapp实现聊天中的接发消息自动滚动、消息定位和回到底部

前言 前言无需多言&#xff0c;想必大家对聊天软件的功能已经很熟悉&#xff0c; 这里不做过多赘述&#xff0c;笔者通过uniapp实现聊天中的接发消息自动滚动、消息定位和回到底部。 代码实现 <template><view class"chat-container"><!-- 消息列表…

《企业司法风险监控系统架构设计:从数据采集到T+1实时预警的完整解决方案》

本文深入探讨了天远大数据在构建企业级司法风险监控平台和风险报告查询系统方面的技术实现与业务应用。平台依托权威、合法的司法数据源&#xff0c;通过实时数据处理与智能分析&#xff0c;为金融、供应链、人力资源等领域提供精准、及时的司法预警和决策支持。它通过灵活的多…