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

分享一种实用redis原子锁的方式

1. setnx(lockkey, 当前时间+过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。

2. get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。

3. 计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey, newExpireTime) 会返回当前lockkey的值currentExpireTime。

4. 判断currentExpireTime与oldExpireTime 是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。

5. 在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。

代码如下:

/**

* 带超时时间的锁

*

* @param lockKey 锁的键值

* @param timeUnit 锁的时间单位

* @param timeout 锁的时间长度

* @param relyOnRedisAvailable 是否依赖redis可用性

* true则redis不可用或异常情况下返回加锁失败;

* false则redis不可用或异常情况下返回加锁成功。

* @return 是否添加锁成功

*/

@Override

public boolean lock(String lockKey, TimeUnit timeUnit, long timeout, boolean relyOnRedisAvailable) {

//获取当前时间

long currentTimeMillis = System.currentTimeMillis();

String repeatSign = UUID.randomUUID().toString().replace("-", "");//重复标记

//获取超时时间的ms

long lockTimeMs = timeUnit.toMillis(timeout);

long setNx;

try {

//这里我们以 超时时间为value+标记

String setLockValue = String.valueOf(currentTimeMillis + lockTimeMs)+repeatSign;

setNx = redisClientUtil.setnx(lockKey, setLockValue);

logger.info("键值[{}]设置的setNx为:{}, setLockValue为:{}", lockKey, setNx, setLockValue);

} catch (Exception e) {

logger.error("{}设置锁异常",lockKey,e);

pubEvent(lockKey,e);

return true;

}

//如果成功了,那么我们就设置超时时间

if (setNx == 1 ) {

logger.info("键值{}获取redis锁成功",lockKey);

try {

redisClientUtil.expire(lockKey, (int)timeUnit.toSeconds(timeout));

} catch (Exception e) {

logger.error("{}设置超时时间异常,异常信息为",lockKey,e);

}

return true;

}

//以下是不成功的处理情况,即 setNx 等于0的时候,我们先获取旧的值

String lockValue = redisClientUtil.getValueByKey(lockKey);

logger.info("键值[{}],设置的lockValue为:{},重复标记为:{}", lockKey, lockValue, repeatSign);

if (StrUtil.isBlank(lockValue)) {

//如果锁value为空,直接返回成功

return true;

}

if(lockValue.contains(repeatSign)){

//如果锁value包含重复标记,则说明其为本次设置,直接返回成功

return true;

}

String lockTime = lockValue.substring(0, lockValue.indexOf("|"));//锁超时时间

if (null == lockTime) {

logger.warn("键值[{}]获取到时间戳为空, 按照获取成功返回!", lockKey);

return true;

} else {

try {

logger.info("键值[{}]redis存储的时间戳:{}, 格式化后:{}", lockKey, lockTime, DateUtil.dateToString(new Date(Long.valueOf(lockTime)), DateUtil.DEFAULT_TIMESTAMP_FORMAT));

} catch (Exception e) {

logger.warn("键值[{}]redis存储的时间戳:{}, 格式化时出现异常,不影响流程", lockKey, lockTime, e);

}

}

if (lockTime != null && Long.valueOf(lockTime)

< System.currentTimeMillis() ) {

String oldValue = redisClientUtil.getSet(lockKey,

String.valueOf(currentTimeMillis + lockTimeMs)+ "|" + repeatSign);

String oldLockTime = oldValue.substring(0, lockValue.indexOf("|"));//锁超时时间

//将两次获取的值对比,这里也就是文章第五条,如果相等说明没有被其他线程修改

if (oldValue != null && oldLockTime.equals(lockTime)) {

//这里用该还要在设置一次超时时间,可以用lua 脚本保持一致性

return true;

}

}

return false;

}

相关文章:

分享一种实用redis原子锁的方式

1. setnx(lockkey, 当前时间过期超时时间) &#xff0c;如果返回1&#xff0c;则获取锁成功&#xff1b;如果返回0则没有获取到锁&#xff0c;转向2。2. get(lockkey)获取值oldExpireTime &#xff0c;并将这个value值与当前的系统时间进行比较&#xff0c;如果小于当前系统时间…...

【华为OD机试】 字符串解密(C++ Java JavaScript Python)

题目描述 给定两个字符串string1和string2。 string1是一个被加扰的字符串。 string1由小写英文字母(’a’’z’)和数字字符(’0’’9’)组成,而加扰字符串由’0’’9’、’a’’f’组成。 string1里面可能包含0个或多个加扰子串,剩下可能有0个或多个有效子串,这些有…...

金三银四,助力你的大厂梦,2023年软件测试经典面试真题(1)(共3篇)

前言 金三银四即将到来&#xff0c;相信很多小伙伴要面临面试&#xff0c;一直想着说分享一些软件测试的面试题&#xff0c;这段时间做了一些收集和整理&#xff0c;下面共有三篇经典面试题&#xff0c;大家可以试着做一下&#xff0c;答案附在后面&#xff0c;希望能帮助到大…...

假如面试官要你手写一个promise

promise 在开发中&#xff0c;经常需要用到promise&#xff0c;promise具有很多特性&#xff0c;这一次将对promise特性进行总结&#xff0c;并从零写一个promise。 步骤一 Promise特点 1&#xff0c;创建时需要传递一个函数&#xff0c;否则会报错2&#xff0c;会给传入的函…...

【leetcode】寻找重复数

题目链接&#xff1a;寻找重复数https://leetcode.cn/problems/find-the-duplicate-number/ 方法一&#xff1a;快慢指针 因为只有一个数字是重复的&#xff0c;且一个数字正好对应一个唯一的下标&#xff0c;所以可以将数组抽象为一个链表&#xff0c;假定数组为{1,2,3,4,5,…...

LeetCode 1247. Minimum Swaps to Make Strings Equal【数学,贪心,字符串】

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

pid控制加热算法,附代码仓库

1、该项目层次化结构清晰&#xff0c;代码框架耦合度低&#xff0c;可复用性、可移植性强。 2、功能代码与底层硬件无直接关联&#xff0c;无需更改上层应用逻辑&#xff0c;只需更改接口文件&#xff0c;即可移植到不同的硬件平台&#xff1b; 3、使用lwrb开源组件、pid开源算…...

一文看懂预训练和自训练模型

说到预训练模型&#xff0c;不得不提迁移学习了&#xff0c;由于很多数据不是标签数据&#xff0c;人工标注非常耗时&#xff0c;神经网络在很多场景下受到了限制。但是迁移学习和自学习的出现&#xff0c;在一定程度上缓解甚至解决了这个问题。我们可以在标签丰富的场景下进行…...

(五十四)大白话索引的页存储物理结构,是如何用B+树来实现的?.md

上一次我们给大家说了主键索引的目录结构&#xff0c;只要在一个主键索引里包含每个数据页跟他最小主键值&#xff0c;就可以组成一个索引目录&#xff0c;然后后续你查询主键值&#xff0c;就可以在目录里二分查找直接定位到那条数据所属的数据页&#xff0c;接着到数据页里二…...

前端Vue代码风格指南

一、命名规范 市面上常用的命名规范&#xff1a; camelCase&#xff08;小驼峰式命名法 —— 首字母小写&#xff09; PascalCase&#xff08;大驼峰式命名法 —— 首字母大写&#xff09; kebab-case&#xff08;短横线连接式&#xff09; Snake&#xff08;下划线连接式&…...

「TCG 规范解读」基础设施架构和协议 (2)

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…...

NodeJs 中的 HTML 模板

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 HTML 模板是一种允许我…...

3.ffmpeg命令行环境搭建、ffmpeg命令行初步了解

在上章,我们讲过: ffmpeg.exe: 主要用于转码或者剪切的应用程序, 也可以从url/现场音频/视频源抓取输入源ffplay.exe: 主要用于播放视频的应用程序,该应用程序源码是开源的,我们后面章节会去源码分析ffprobe.exe: 主要用于分析视频码流的应用程序, 可以获取媒体文件的详细信息,…...

Kubernetes初始化容器

初始化容器 之前了解了容器的健康检查的两个探针&#xff1a;liveness probe&#xff08;存活探针&#xff09;和readiness probe&#xff08;可读性探针&#xff09;的使用方法&#xff0c;我们说在这两个探针是可以影响容器的生命周期的&#xff0c;包括我们之前提到的容器的…...

leetcode: Swapping Nodes in a Linked List

leetcode: Swapping Nodes in a Linked List1. 题目描述2. 题目解答3. 总结1. 题目描述 You are given the head of a linked list, and an integer k.Return the head of the linked list after swapping the values of the kth node from the beginning and the kth node f…...

Nydus 在约苗平台的容器镜像加速实践

文 | 向申 约苗平台运维工程师 关注云原生领域 本文字数 9574阅读时间24分钟 本文是来自向申同学的分享&#xff0c;介绍了其在 K8s 生产环境集群部署 Nydus 的相关实践。 Nydus 是蚂蚁集团&#xff0c;阿里云和字节等共建的开源容器镜像加速项目&#xff0c;是 CNCF Dragon…...

企业对不同形态CRM系统价格需求不同

很多企业在选型时关心CRM客户管理系统的价格&#xff0c;有人对CRM的价格完全没有概念&#xff0c;也有的人先问价格再看其他。CRM价格在系统选型中到底有多重要&#xff1f;不同类型CRM系统的价格是否有所不同&#xff1f; CRM的不同产品形态也会影响价格 通常情况下&#x…...

「JVM 高效并发」线程安全

面向过程编程&#xff0c;把数据和过程分别作为独立的部分考虑&#xff0c;数据代表问题空间中的客体&#xff0c;程序代码则用于处理这些数据&#xff1b;面向对象编程&#xff0c;把数据和行为都看做对象的一部分&#xff0c;以符合现实世界的思维方式来编写和组织程序&#…...

微信扫码登录

一、准备工作 微信开发者平台&#xff1a;https://open.weixin.qq.com 1、注册 2、邮箱激活 3、完善开发者资料 4、开发者资质认证&#xff1a;仅能企业注册&#xff08;后面提供学习的使用渠道&#xff09;准备营业执照&#xff0c;1-2个工作日审批、300元 5、创建网站应用&…...

Unity协程的简单应用

Unity协程是一种特殊的函数&#xff0c;可以让你在Unity中创建一种类似于多线程的异步操作。它可以在需要等待某个操作完成时&#xff0c;暂停执行当前代码&#xff0c;等待某个条件满足后再继续执行。 在一般情况下 unity中调用函数时&#xff0c;函数将运行到完成状态&#x…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...