当前位置: 首页 > news >正文

Redisson相关知识

RedissonFairLock公平锁中,list和zset的作用是什么?里面放的是什么?

好问题 👍,你问到 Redisson 的公平锁 (RedissonFairLock) 内部用到的 listzset,这是它跟普通 RLock 最大的区别点。

我来拆开讲 👇


1️⃣ 普通 RLock 的做法

  • RLock 用的是一个 hash 结构

    • key: 锁名
    • field: 线程标识(uuid + threadId)
    • value: 重入次数

锁的续期靠看门狗,解锁时 hash 中计数减到 0 就删除。
👉 它 不保证公平性,只是 CAS 抢锁,谁快谁拿到。


2️⃣ 公平锁 RedissonFairLock 多了什么?

为了保证 FIFO 公平性,RedissonFairLock 引入了 两个额外的数据结构

  • List (队列 list)

    • 作用:保存 等待线程的队列顺序(谁先来,谁排在前面)
    • 里面放的内容:每个线程的 唯一标识 (uuid:threadId)
    • 类似一个排号系统,先进先出。
  • ZSet (有序集合 zset)

    • 作用:保存 线程对应的允许获取锁的时间点(timestamp)

    • 里面放的内容:

      • member = 线程标识 (uuid:threadId)
      • score = 可获取锁的时间戳(毫秒值)

👉 为什么要用 zset?
因为即使排在队列最前面的线程,也必须等前一个线程释放锁,才能根据时间戳判断“自己能不能获取锁”。


3️⃣ 执行流程

  • 线程请求锁

    1. 加入 list,表示排队
    2. 加入 zset,标记自己最早能获取锁的时间
  • 线程获取锁

    1. 检查自己是否在 list 队首
    2. 检查当前时间是否 ≥ 自己在 zset 里的可执行时间
    3. 满足条件 → 获取锁成功
    4. 否则继续阻塞等待
  • 释放锁

    1. 删除自己在 list 和 zset 里的数据
    2. 通知下一个线程(队首 + 时间满足)去尝试获取锁

4️⃣ 对比总结

数据结构存的内容作用
Hash (普通锁就有)threadId -> 重入次数记录当前持有锁的线程
List线程标识列表 [t1, t2, t3...]保证排队顺序(FIFO)
ZSetthreadId -> timestamp控制线程最早能获取锁的时间

👉 list 保证 顺序zset 保证 时机

以及如果线程过期时间到了,还在执行怎么办?这里不能锁续约吗?

好问题 👍,你盯住了 Redisson 公平锁 (RedissonFairLock) 和普通锁的差别点,两个疑问都非常关键。
我分两部分解释 👇


1️⃣ 为什么要“等前一个线程释放锁 + 时间戳检查”

公平锁的目标:谁先来,谁先拿锁
Redisson 的公平锁用 list + zset 来实现这个逻辑:

  • list → 保证顺序,谁排在前面,谁先有资格尝试。
  • zset → 保存“该线程可以获取锁的最早时间”。

流程:

  1. 线程 A 获取到锁,它的占有时间假设是 leaseTime = 10s

  2. 线程 B 来了,排进 list 队列,同时在 zset 里记录一个时间戳 now + 10s

    • 表示 只有 A 的锁过期/释放后,B 才能开始竞争
  3. 当 A 释放锁时,B 才会被唤醒去检查:

    • 自己是不是在队列头 (list 首元素)
    • 当前时间 ≥ 自己在 zset 中的 score(可获取时间)
    • 满足条件,才能真正拿到锁。

👉 这样避免了“后来的线程插队”,保证 FIFO 公平性。
如果没有时间戳,A 可能刚释放锁,B、C 一起去争,结果可能 C 抢到,就不公平了。


2️⃣ 如果线程 leaseTime 到了,还在执行怎么办?

这是一个非常现实的问题。

  • 普通锁 (RLock):有 看门狗机制,会自动续期,保证执行中的线程不会因为 leaseTime 到期而丢锁。

  • 公平锁 (FairLock)没有看门狗续期机制❌。

    • 因为公平性需要依赖 时间戳 来判断“下一个线程能否获取锁”。
    • 如果支持自动续期,可能会让后面的线程一直卡住,永远轮不到。

👉 所以在 Redisson 的公平锁里:

  • 线程必须在 leaseTime 内完成任务。
  • 如果没完成,锁会过期释放,后续线程就可能拿到锁,导致并发执行。

3️⃣ 总结

  • “排在队首还要等时间戳” → 确保前一个线程释放锁之后,下一个线程按顺序、按时机才能拿到锁,避免插队。
  • 公平锁没有自动续期 → 因为续期会破坏公平性。
  • 如果任务耗时不确定,不推荐用公平锁,可以用普通 RLock(有看门狗自动续期)。

那么,如果网络波动,唤醒B的包丢失了,时间在流逝,那么最终也会轮到C先抢到锁,B在队列中的信息会被自动清除吗?

你问到的这个场景很真实 👍:

如果 B 的唤醒包丢了,时间在流逝,最后是不是 C 会先拿到锁?那 B 在队列里的信息怎么办,会被自动清理吗?

我来详细解释 👇


1️⃣ B 的“唤醒丢失”可能吗?

RedissonFairLock 的实现里:

  • 锁释放时,会用 publish 通知 下一个等待线程(而不是广播)。
  • 这个通知依赖 Redis Pub/Sub
  • 如果 消息丢失(网络波动,或者 B 进程崩溃没处理到),B 的确可能错过抢锁的时机。

2️⃣ 时间流逝后会怎样?

假设:

  • A leaseTime = 10s
  • B 被安排的可抢锁时间 = now + 10s
  • C 被安排的可抢锁时间 = now + 20s

如果 B 没有正常抢锁

  • 到了 20s,C 的 score 到期了。
  • C 就会尝试去拿锁(条件是自己是 list 队首 + 时间满足)。
  • 这时,Redis 的队列会把 B 从 list/zset 中清理掉,让 C 成为新的首元素。

3️⃣ B 的信息是如何清除的?

Redisson 在公平锁的实现里有 清理逻辑

  • 每次有线程尝试获取锁时,会检查队首元素对应的线程。
  • 如果队首线程的等待时间已经过了,但它没去拿锁(比如 B 因为丢包挂住了),就会把它从 list 和 zset 中移除。
  • 这样,后续线程(C)才能顺利继续。

👉 也就是说:

  • B 不会永久卡在队首
  • 一旦 B 超时没动作,它会被移除,C 就能顶上。

4️⃣ 总结

  • B 丢失唤醒信号后,确实可能错过抢锁机会。
  • RedissonFairLock 通过 list + zset 清理机制 避免“僵尸节点”卡死队列。
  • 最终 C 会顺利拿到锁,公平性依然能保证。
  • 但对 B 来说,它就“饿死”了,需要重新发起加锁请求。
http://www.dtcms.com/a/342753.html

相关文章:

  • 数据结构青铜到王者第一话---数据结构基本常识(1)
  • 零基础从头教学Linux(Day 17)
  • 在职老D渗透日记day23:sqli-labs靶场通关(第29关-31关)http参数过滤
  • [软件开发技术栈]从MVVM到MVC
  • 大模型提示词工程背后的原理:深入理解Prompt Learning(提示学习)
  • 【Dify(v1.x) 核心源码深入解析】prompt 模块
  • 单智能体篇:Prompt工程艺术
  • 【运维进阶】Shell 函数的知识与实践
  • CTFSHOW | 其他篇题解(一)web396-web416
  • 学习日志39 python
  • 华为iVS1800接入SVMSPro平台
  • Web3 的发展挑战:技术、监管与生态的多重困境
  • 使用C++11改进工厂方法模式:支持运行时配置的增强实现
  • 【Ansible】将文件部署到受管主机1:文件模块
  • Autoware Universe 感知详解 | 第二节 宏观认识Autoware Universe感知模块整体架构
  • C++中的内存管理(二)
  • 第四章:大模型(LLM)】07.Prompt工程-(6)受限生成和引导生成
  • 机械试验台功能量具平台:铸铁工装平台
  • 阿里云对象存储OSS之间进行数据转移教程
  • 小迪安全v2023学习笔记(六十八讲)—— Java安全原生反序列化SpringBoot攻防
  • iOS沙盒机制
  • 【系统信息相关】datecal命令
  • React + Antd+TS 动态表单容器组件技术解析与实现
  • (栈)Leetcode155最小栈+739每日温度
  • Python爬虫实战:研究puzzle,构建谜题类数据采集分析系统
  • 编程语言与存储过程:业务处理的速度与取舍
  • 3ds Max 渲染动画总模糊?
  • 基于stm32的智能建筑能源管理系统/基于单片机的能源管理系统
  • 【Java SE】认识数组
  • 【Protues仿真】基于AT89C52单片机的舵机和直流电机控制