【Redis 开发】分布式锁中的常见问题和Lua脚本

ops/2025/2/11 21:56:23/

分布式锁中的问题

分布式锁中我们设置的过期时间:
如果有一个线程获取锁之后在进行操作时,到达了锁的过期时间,之后就会有别的线程获得锁,如果这时,第一个线程执行完成后释放锁,就会将第二个锁的线程删除

针对这个情况如何改进:

  1. 在获取锁时存入线程标示(可以用UUID)
  2. 在释放锁时先获取锁中的线程标示,判断是否与当前线程标识一致
  3. 如果一致则释放锁
  4. 如果不一致则不释放锁

改进分布式锁添加释放锁的判断

public class SimpleRedisLock implements ILock{private String name;private StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}private static final String key_prefix="lock:";private static final String id_prefix= UUID.randomUUID().toString()+"-";@Overridepublic boolean tryLock(long timeoutSec) {//获取线程的标识String threadId= id_prefix+Thread.currentThread().getId();Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(key_prefix + name, threadId, timeoutSec, TimeUnit.SECONDS);//自动拆箱的返回return Boolean.TRUE.equals(aBoolean);}@Overridepublic void unlock() {//获取线程标识String threadid = id_prefix + Thread.currentThread().getId();//获取锁中的标识String s = stringRedisTemplate.opsForValue().get(key_prefix + name);//判断标识是否一致if(threadid.equals(s)) {//释放锁stringRedisTemplate.delete(key_prefix+name);}}
}

上述我们做了修改进行判断,但是还存在一种极端情况,当线程操作完毕需要释放锁的时候,这个时候已经判断完毕,但是由于比如说垃圾回收等问题对线程的释放操作进行阻塞,这个时候如果超过等待时间,这是还是会出现上述问题,在阻塞结束之后,会删除其他线程的锁

要彻底避免这种情况的发生,需要将判断锁标识的动作与释放锁标识的动作进行原子性操作,此时就会用到Lua脚本

Lua脚本

Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性,Lua脚本时一种编程语言
地址:https://www.runoob.com/lua/lua-tutorial.html

编写Lua脚本

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by LENOVO.
--- DateTime: 2024/4/26 19:01
---比较线程标识与锁中的标识是否一致
if(redis.call('get',KEY[1]) == ARGV[1]) then--- 释放锁资源return redis.call('del',KEY[1])
end
return 0

调用Lua脚本:

    @Overridepublic void unlock() {//调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(key_prefix+name),id_prefix+Thread.currentThread().getId());}

其中的UNLOCK_SCRIPT是脚本对象,需要提前进行定义

    //设置脚本对象private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static{UNLOCK_SCRIPT =new DefaultRedisScript<>();UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}

http://www.ppmy.cn/ops/29559.html

相关文章

三维坐标点按剖面分类

一、写在前面 ①配套文件&#xff1a;根据剖面对三维坐标点&#xff08;X,Y,Z&#xff09;分类资源-CSDN文库 ②脱敏处理&#xff1a;蚀变数据已采用随机数生成覆盖 ③剖面坐标按顺序排列在“剖面坐标点.xlsx”文件中 二、3点确定空间中平面方程 原理&#xff1a; 设3点A&…

Redis线程模型及性能优化概述

redis线程模型&#xff1a; 网络模块命令处理 redis的性能&#xff1a; 一个取决于物理内存&#xff0c;另一个是对于socket请求的处理速度。 4.0以前 单线程模式 请求流程&#xff1a;对于一个请求&#xff0c;线程会根据操作产生相应的事件&#xff08;读&#xff0c;写事…

政安晨:【Keras机器学习示例演绎】(二十九)—— 利用卷积 LSTM 进行下一帧视频预测

目录 简介 设置 数据集构建 数据可视化 模型构建 模型训练 帧预测可视化 预测视频 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&…

微软如何打造数字零售力航母系列科普04 - 微软联合Adobe在微软365应用程序中工作时推出新的生成式AI功能

微软和Adobe正在合作&#xff0c;将情境营销见解和工作流程引入微软Copilot&#xff0c;以提供生成的人工智能功能&#xff0c;使营销人员和营销团队能够在自然的工作流程中实现更多目标。 这些新的集成功能将在生产力和协作工具&#xff08;如Outlook、Teams和Word&#xff0…

leetcode2639--查询网格图中每一列宽度

1. 题意 求每一列中最长整数的长度。 2. 题解 2.1 直接模拟 class Solution { public:void test(int a1, int a2) {if (a1 ! a2)printf("%d ne %d\n", a1, a2);}vector<int> findColumnWidth(vector<vector<int>>& grid) {vector<int&g…

Vitis HLS 学习笔记--MAXI手动控制突发传输

目录 1. 简介 2. MAXI 突发传输详解 2.1 突发传输的前置条件 2.2 hls::burst_maxi 详解 2.2.1 基本知识 2.2.2 hls::burst_maxi 构造函数 2.2.3 hls::burst_maxi 读取方法 2.2.4 hls::burst_maxi 写入方法 2.3 示例一 2.4 示例二 3. 总结 1. 简介 这篇文章探讨了在…

windows 驱动开发-DMA技术(三)

在早期&#xff0c;是按照基于包或者基于流的方式来描述DMA的&#xff0c;不过这个描述可能不准确&#xff0c;故在Vista之后修改为使用数据包/使用公共缓冲区的系统DMA。 简单的解释一下基于包和基于流的说法的原因&#xff0c;数据包是指一个个基于一定大小的数据块&#xf…

分类规则挖掘(三)

目录 四、贝叶斯分类方法&#xff08;一&#xff09;贝叶斯定理&#xff08;二&#xff09;朴素贝叶斯分类器&#xff08;三&#xff09;朴素贝叶斯分类方法的改进 五、其它分类方法 四、贝叶斯分类方法 贝叶斯 (Bayes) 分类方法是以贝叶斯定理为基础的一系列分类算法的总称。贝…