基于Redisson实现重入锁
一. 分布式锁基础
在分布式系统中,当多个客户端(应用实例)需要访问同一资源时,可以使用分布式锁来确保同一时刻只有一个客户端能访问该资源。Redis作为高性能的内存数据库,提供了基于键值对的分布式锁实现,通常采用SETNX命令(即SET if Not eXists)来设置锁。
Redis的分布式锁大致实现流程如下:
- 客户端请求获取锁:通过
SETNX命令设置一个锁键(如lock:<resource>)。 - 锁被设置成功时,客户端可以访问资源;否则,它会等待或返回获取失败的结果。
- 客户端在完成工作后,释放锁:通过
DEL命令删除锁键。
二. 可重入锁
在一个线程或进程中,如果该线程/进程已经获取了锁,那么它可以重复获取该锁,而不会发生死锁问题。也就是说,同一线程/进程可以多次获取锁,而每次释放锁时都需要释放一次,直到所有的锁请求都被释放。
对于分布式系统中的可重入锁,它确保:
- 当一个客户端(通常是线程或进程)已经持有锁时,它可以继续请求该锁而不会被阻塞或进入死锁。
- 锁的计数是线程级别的,客户端每次请求锁时都需要将锁的计数增加,释放锁时则减少计数,直到计数为零时才完全释放锁。
三. Redis实现可重入锁的步骤
1. 使用SET命令(或SETNX命令)来获取锁
- 锁是由一个特定的Redis键(例如,
lock:<resource>)表示的。 - 锁的值通常是一个标识符,例如,客户端的
UUID,或者一个线程标识符。这个值用于确保同一个客户端可以重复获取锁。
2. 记录锁的持有者
- 当客户端请求锁时,它不仅设置一个标识该锁的键(如
lock:<resource>),而且还设置该锁的值(如UUID)。这样,如果该锁已经存在且值不是当前客户端的标识符,则客户端无法获得锁。
3. 锁的可重入性
- 在可重入锁中,客户端获取锁时,如果该客户端的标识符(如
UUID)已经在锁值中,则客户端可以继续获取锁,并且需要将锁的“持有次数”增加。 - 可以通过键值对的计数来实现这一点。每次客户端请求锁时,Redis可以增加锁的计数。当客户端释放锁时,Redis会减少锁的计数。
4. 锁的过期时间
- 为了防止死锁,Redis的锁通常会设置一个过期时间,通常是
SET命令的EX选项(设置过期时间)。这样,如果客户端在持有锁的过程中发生故障,锁会在一定时间后自动释放。 - 可重入锁的一个实现方式是,客户端在每次获取锁时刷新过期时间,确保锁在可重入期间不会过期。
5. 释放锁
- 当客户端完成工作后,它会释放锁。每次释放锁时,它会检查当前的锁计数:
- 如果锁计数大于1,表示该客户端还需要继续持有锁,于是减少计数。
- 如果锁计数为1,则客户端完全释放锁,通过删除锁键(如
DEL)来释放该资源。
四 LUA 脚本实现简单重入锁

获取锁的 Lua 脚本:
local key = KEYS[1]; -- 锁的key
local threadId = ARGV[1]; -- 线程唯一标识
local releaseTime = ARGV[2]; -- 锁的自动释放时间-- 判断是否存在
if (redis.call('EXISTS', key) == 0) then-- 不存在,获取锁redis.call('HSET', key, threadId, '1');-- 设置有效期redis.call('EXPIRE', key, releaseTime);return 1; -- 返回结果
end;-- 锁已经存在,判断threadId是否是自己
if (redis.call('HEXISTS', key, threadId) == 1) then-- 是自己,获取锁,重入次数+1redis.call('HINCRBY', key, threadId, '1');-- 设置有效期redis.call('EXPIRE', key, releaseTime);return 1; -- 返回结果
end;return 0; -- 代码走到这里,说明获取锁的不是自己,获取锁失败
释放锁的 Lua 脚本:
local key = KEYS[1]; -- 锁的key
local threadId = ARGV[1]; -- 线程唯一标识
local releaseTime = ARGV[2]; -- 锁的自动释放时间-- 判断当前锁是否还是被自己持有
if (redis.call('HEXISTS', key, threadId) == 0) thenreturn nil; -- 如果已经不是自己,则直接返回
end;-- 是自己的锁,则重入次数减1
local count = redis.call('HINCRBY', key, threadId, -1);-- 判断是否重入次数是否已经为0
if (count > 0) then-- 大于0说明不能释放锁,重置有效期然后返回redis.call('EXPIRE', key, releaseTime);return nil;
else-- 等于0说明可以释放锁,直接删除redis.call('DEL', key);return nil;
end;
相关文章:
基于Redisson实现重入锁
一. 分布式锁基础 在分布式系统中,当多个客户端(应用实例)需要访问同一资源时,可以使用分布式锁来确保同一时刻只有一个客户端能访问该资源。Redis作为高性能的内存数据库,提供了基于键值对的分布式锁实现,…...
Java文件操作的简单示例
使用原生库 创建空白文件 package com.company; import java.io.File; import java.io.IOException;public class Main {public static void main(String[] args) {File f new File("newfile.txt");try {boolean flag f.createNewFile();System.out.println(&quo…...
删除与增加特定行
1.删除特定行 new_df <- df[-c(4), ] #删除第4行 new_df <- df[-c(2:4), ] #去除第2-4行 new_df <- subset(df, col1 < 10 & col2 < 6) #删除特定第一列<10和第二列<6的行。按名字删除 无论行列,可以找出对应索引或构造相同长…...
动态规划六——两个数组的dp问题
目录 题目一——1143. 最长公共子序列 - 力扣(LeetCode) 题目二——1035. 不相交的线 - 力扣(LeetCode) 题目三——115. 不同的子序列 - 力扣(LeetCode) 题目四—— 44. 通配符匹配 - 力扣(…...
项目优化之策略模式
目录 策略模式基本概念 策略模式的应用场景 实际项目中具体应用 项目背景: 策略模式解决方案: 计费模块策略模式简要代码 策略模式基本概念 策略模式(Strategy Pattern) 是一种行为型设计模式,把算法的使用放到环境类中,而算…...
[读书日志]从零开始学习Chisel 第四篇:Scala面向对象编程——操作符即方法(敏捷硬件开发语言Chisel与数字系统设计)
3.2操作符即方法 3.2.1操作符在Scala中的解释 在其它语言中,定义了一些基本的类型,但这些类型并不是我们在面向对象中所说的类。比如说1,这是一个int类型常量,但不能说它是int类型的对象。针对这些数据类型,存在一些…...
三子棋游戏
目录 1.创建项目 2.主函数编写 3.菜单函数编写 4.宏定义棋盘行和列 5.棋盘初始化 6.打印棋盘 7.玩家下棋 8.电脑下棋 9.平局判断 10.输赢判断 11.game函数 三子棋游戏(通过改变宏定义可以变成五子棋),玩家与电脑下棋 1.创建项目…...
MyBatis执行一条sql语句的流程(源码解析)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 MyBatis执行一条sql语句的流程(源码解析) MyBatis执行sql语句的流程加载配置文件加载配置文件的流程 创建sqlsessionFactory对象解析Mapper创建sqlses…...
【电机控制】低通滤波器及系数配置
【电机控制】低通滤波器及系数配置 文章目录 [TOC](文章目录) 前言一、低通滤波器原理二、理论计算三、代码四、参考资料总结 前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、低通滤波器原理 二、理论计算 三、代码 //低通滤波 pv->Ealpha…...
ArcgisServer过了元旦忽然用不了了?许可过期
昨天过完元旦之后上班发现好多ArcgisServer的站点运行出错了,点击日志发现,说是许可过去,也就是当时安装ArcgisServer时读取的ecp文件过期了,需要重新读取。 解决方法 1.临时方法,修改系统时间,早于2024年…...
如何在不丢失数据的情况下从 IOS 14 回滚到 IOS 13
您是否后悔在 iPhone、iPad 或 iPod touch 上安装 iOS 14?如果你这样做,你并不孤单。许多升级到 iOS 14 beta 的 iPhone、iPad 和 iPod touch 用户不再适应它。 如果您在正式发布日期之前升级到 iOS 14 以享受其功能,但您不再适应 iOS 14&am…...
【算法刷题】链表
文章目录 环形链表判断是否有环找出环的入口位置 双指针反转链表(Reverse a Linked List)移除链表中的指定元素(Remove Linked List Elements) 环形链表 判断是否有环 环形链表是指链表中的某些节点的 next 指针指向了链表中的某…...
计算机网络 —— 网络编程实操(1)(UDP)
计算机网络 —— 网络编程实操(UDP) 套接字端口套接字的定义为什么需要套接字? 套接字的分类1. 按照通信协议分类2. 按照地址族(Address Family)分类3. 按照通信模式分类 socket APIsockaddr结构 使用接口套接字初始化…...
selenium 确保页面完全加载
在使用Python和Selenium进行Web自动化时,确保页面完全加载是非常重要的。为了实现这一点,Selenium提供了两种主要类型的等待:显式等待(Explicit Waits)和隐式等待(Implicit Waits)。此外&#x…...
[极客大挑战 2019]HardSQL 1
看了大佬的wp,没用字典爆破,手动试出来的,屏蔽了常用的关键字,例如:order select union and 最搞的是,空格也有,这个空格后面让我看了好久,该在哪里加括号。 先传入1’ 1试试&#…...
vip与haproxy构建nginx高可用集群传递客户端真实ip
问题 系统使用了vip与haproxy实现高可用以及对nginx进行负载均衡,但是发现在上游的应用服务无法拿到客户端的请求ip地址,拿到的是主haproxy机器的ip,以下是nginx与haproxy的缩减配置: location ~* ^/(xx|xx) {proxy_pass http:/…...
Easticsearch介绍|实战?
Elasticsearch 是一个分布式的、RESTful 风格的搜索和数据分析引擎,适用于各种用例,如日志分析、全文搜索、实时应用监控等。它设计用来处理大量数据,并且可以快速地提供相关的搜索结果。以下是一些 Elasticsearch 的实战应用场景以及如何在这…...
Python图形界面(GUI)Tkinter笔记(二十一):Messagebox信息提示功能控件
messagebox 就像是 tkinter 库里的一个好帮手,它能帮你弹出各种各样的消息框给用户看。这些消息框可以告诉用户很多东西,比如提示、警告或者错误信息之类的。在 tkinter 库里,messagebox 这个模块有很多不同的函数,每个函数都能弹出一种特定的消息框。用这些函数,开发者可…...
vue3+ts+element-plus 表单el-form取消回车默认提交
问题描述:在表单el-form中的el-input中按回车后,页面会刷新,url也会改变, 回车前: 回车后: 相关代码: 解决方法1:在 el-form 上阻止默认的 submit 事件,增加 submit.pre…...
Web Services 简介
Web Services 简介 1. 引言 Web Services 是一种基于网络的软件服务,它允许不同的应用程序在互联网上相互通信和交互。这种技术是基于开放的互联网标准,如HTTP、XML、SOAP和WSDL,使得不同平台和编程语言的应用程序能够轻松地实现互操作性。Web Services 的出现,极大地推动…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
python基础语法Ⅰ
python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器,来进行一些算术…...
高保真组件库:开关
一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...
