首页 > 其他分享 >Reids实现分布式锁

Reids实现分布式锁

时间:2024-08-05 21:50:48浏览次数:14  
标签:String 实现 Reids uuid value jedis key 线程 分布式

基于SETNX

如果 key不存在,则SETNX成功返回1,如果这个key已经存在了,则返回0。 

import redis.clients.jedis.Jedis;
public class SetNxExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");

        String key = "my_key";
        String value = "my_value";
        // 使用 SETNX 命令
        if (jedis.setnx(key, value)== 1) {try{
                //处理业务
            }catch(){
            
            }finally{
                jedis.del(key); //释放锁
            }
            
        } 
        // 关闭连接
        jedis.close();
    }
}

这里我们实现了简单的互斥锁,但是有个问题,如果持有锁的线程挂掉,锁将一直存在,导致死锁。

天才的你肯定想到了,只要给这个key设置一个过期时间就可以。我们通过Expire(key,time)命令设置过期时间,在加锁的时候同时设置一个过期时间。改进代码:

import redis.clients.jedis.Jedis;
public class SetNxExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
       
        String key = "my_key";
        String value = "my_value";
        // 使用 SETNX 命令
        if (jedis.setnx(key, value)== 1) {
            jedis.expire(key , 100);
            try{
                //处理业务
            }catch(){
            
            }finally{
                jedis.del(key); //释放锁
            }
            
        } 
        // 关闭连接
        jedis.close();
    }
}

设置了时间解决了死锁问题,但是这里又出现新问题了,设置key和设置过期时间不是原子操作,如果key设置成功,但是过期时间设置失败了,又出现死锁了。另外如果线程A执行时间过长,key到期了释放锁,这个时候线程B拿到锁,此后线程A执行结束,释放锁,将B的锁释放了。

解决方法:

将当前线程id或者使用uuid设为value值,这样在释放的时候可以判断是否是当前线程持有的锁。使用SET的扩展方式使设置key和设置过期时间的具有原子性。

String uuid = String uuid  = UUID.randomUUID().toString();
if("OK".equals(jedis.set(key, uuid,newSetParams().nx().ex(100)))){ //加锁
    try {
        //业务处理
    }catch(){

     }finally{
       if(uuid.eauls(jedis.get(key))){
           jedis.del(key); //释放锁
       }
    }
}
这里if判断和释放锁不是原子操作,可能会释放其他线程的锁.使用lua脚本解决.
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
    else
    return 0
    end

改写后的代码:

String uuid = String uuid  = UUID.randomUUID().toString();
if("OK".equals(jedis.set(key, uuid,newSetParams().nx().ex(100)))){ //加锁
    try {
        //业务处理
    }catch(){

     }finally{
       String luaSript = "" +
                "if redis.call('get', KEYS[1]) == ARGV[1] then\n" +
                "    return redis.call('del', KEYS[1])\n" +
                "    else\n" +
                "    return 0\n" +
                "    end";
        jedis.eval(luaSript, Collections.singletonList(key),Collections.singletonList(value));
    }
}

 

以上方案可以基于redis的SETNX实现分布式锁。

标签:String,实现,Reids,uuid,value,jedis,key,线程,分布式
From: https://www.cnblogs.com/LH-up-blogs/p/18344116

相关文章

  • A087-基于SpringBoot+Vue实现的超市管理系统(源码+数据库+部署文档+部署演示视频)
    (======查看博主个人介绍,有源码获取联系方式========)这里提供的系统介绍和演示视频,展示了一个基于SpringBoot和Vue实现的超市管理系统,采用了前后端分离的架构方式。系统设计包括管理员和员工两种角色,涵盖了销售管理、人事管理、个人中心、库存管理、会员管理、系统管理和商品管......
  • border-image实现与圆角渐变边框实例页面
    <h4>1.父元素圆角</h4><divclass="father"><divclass="border-gradient">圆角渐变边框</div></div><h4>2.clip-path剪裁</h4><divclass="border-gradientclip-path">圆角渐变边框</div&......
  • 人才招聘系统的设计与实现/PHP/招聘网站/计算机设计/毕业项目
    摘    要随着互联网时代的来临,当今世界的生活的节奏变的越来越快,大众对工作效率的标准也变得越来越高,报名参加人才招聘会耗时耗力,无目的性的信息搜索任务量大,且成功的可能性低。为了能够方便大众利用互联网投递个人简历寻找适宜的就业机会,也使企业可以利用在线互联网进......
  • Vue+live2d实现虚拟人物互动(一次体验叙述)
    目录故事的开头:最终的实现效果:实现步骤:第一步:下载重要文件第二步:创建vue项目文件,将刚下载文件拷贝到public目录下第三步:在index.html文件中引入js第四步:使用,去创建人物初步用法基础用法人物模型替换高级用法(只有一些模型提供)事件监听显示对话框完整代码:参考文......
  • 【数值计算方法】2&3维高斯积分的python实现
    目录二维高斯积分三维高斯积分验证本文只给出pythont实现和例题,数学推导见【数值计算方法】数值积分&微分-python实现-FE-有限元鹰-博客园二维高斯积分python实现二维高斯积分:defInteg2dGuassLegendre(f,lowLimit:List[float]=[-1,-1],......
  • C#自定义快捷操作键的实现 - 开源研究系列文章
          这次想到应用程序的快捷方式使用的问题。      Windows已经提供了API函数能够对窗体的热键进行注册,然后就能够在窗体中使用这些注册的热键进行操作了。于是笔者就对这个操作进行了整理,将注册热键操作写成了帮助类,并且用此博文来记录这个使用DEMO,便于其他读者......
  • go的并发任务如何优雅的实现错误终止
    errgroup使用案例在Go语言中,并发任务通常通过goroutine来实现,而错误处理和任务终止的优雅性则依赖于适当的同步机制和错误传播策略。场景:管理一个任务的一组子任务,每个子任务一个协程每个子任务必须保证都成功,一个出现失败应当立马停止所有子任务想知道子任务失败的原因......
  • 是否有对数累积分布函数 (CDF) 和分位数函数的数值稳定的 Python 实现?
    我正在寻找以下函数的数值稳定实现。由于我的应用涉及t分布,所以我这里以t分布为例。LogCDF#NaivePythonimplementationofthefunctionIneedimportscipyimportnumpyasnpdeft_log_cdf(x,df):p=scipy.stats.t.cdf(x,df=df)returnnp.log(......
  • 基于神经网络的手写数字识别及其ZYNQ实现
        基于MNIST数据集的手写数字识别是神经网络(NeuralNetwork)的经典应用。    本文将讨论一种名为“ZYNET”的全连接神经网络框架,它可以自动生成针对FPGA的硬件实现架构。我们以手写数字识别为例,在ZYNQ平台上对该架构进行验证。本章包括以下几个部分:1环境配......
  • Redis分布式锁防止缓存击穿
    一、Nuget引入StackExchange.Redis、DistributedLock.Redis依赖二、使用 StackExchange.Redis对redis操作做简单封装publicclassRedisHelper{privatestaticConnectionMultiplexer_redis;privatestaticstring_connectionString;//静态构造函数,确保在程序启动时......