首页 > 数据库 >基于redis实现分布式锁

基于redis实现分布式锁

时间:2024-07-27 17:57:51浏览次数:10  
标签:基于 name 获取 redis String 线程 stringRedisTemplate 分布式

       分布式锁

e0535635a48c41e09b0ebefb41fa7ab3.png

f510bf8260ba4a16a911680ffceb2dc2.png

1.基于redis实现分布式锁

422c57ef7b244ce681b69b8b5ad38e3a.png

注意:这里设置过期时间,是为了预防死锁。如果某个线程获取了锁,但还没等它执行完业务,释放锁。服务器就宕机了,那么就不会有人再去释放锁,出现了死锁问题。

简单业务代码:

public interface ILock {
    boolean tryLock(long timeoutSec);

    //删除锁
    void unLock();
}
public class SimpleRedisLock implements ILock {
    //name 业务名字 (要知道是我哪个业务获取了锁,不可能所有业务获取一把锁啊)
    private String name;

    private StringRedisTemplate stringRedisTemplate;

    private static String KEY_PREFIX = "lock:";

    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 尝试获取锁
     *
     * @param timeoutSec 锁的过期时间
     * @return 是否成功获取锁
     */
    @Override
    public boolean tryLock(long timeoutSec) {
        long threadId = Thread.currentThread().getId();
        String threadName = Thread.currentThread().getName();
        Boolean success = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PREFIX + this.name, threadName + threadId, timeoutSec, TimeUnit.SECONDS);
        //不直接返回success是因为它是Boolean类型(可能为null),返回值是boolean(不能为null),有一个自动拆箱。可能会空指针异常
        return Boolean.TRUE.equals(success);
    }

    @Override
    public void unLock() {
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + this.name);
        if (id.equals(threadId)) {//只有当我释放锁的线程和我当时获取锁的线程是同一个时,才能释放锁!
            stringRedisTemplate.delete(KEY_PREFIX + this.name);
        }
    }
}

bdd28bd25a50434d9b8624b118d2864a.png

2.基于Redisson实现分布式锁

业务代码:

lua脚本可以保证操作的原子性,类似事务,同时会执行成功/失败。

Redisson实现分布式锁的优点:

1.添加了Watch dog 可以给锁续期。

2.没抢到锁的线程会进行尝试等待。在高并发情况下增加分布式锁的使用性能。

3.所有的redis命令是基于lua脚本完成的。

Redisson实现分布式锁的可重入性

大概流程:底层通过hash结构存储,hash中的key存储的是获取锁的线程id,value是重入的次数。

在一个线程中,每次获取锁,重入次数+1,释放锁,重入次数-1。

对于上述代码:执行add1方法时,第一次获取锁,重入次数为1。执行add2方法中的获取锁,重入次数为2。add2释放锁,重入次数 - 1,为1。add1方法最后释放锁重入次数为0。删除锁信息

小结:

标签:基于,name,获取,redis,String,线程,stringRedisTemplate,分布式
From: https://blog.csdn.net/qq_64064246/article/details/138520192

相关文章

  • 基于微信小程序+SpringBoot+Vue的校园自助打印系统(带1w+文档)
    基于微信小程序+SpringBoot+Vue的校园自助打印系统(带1w+文档)基于微信小程序+SpringBoot+Vue的校园自助打印系统(带1w+文档)管理信息可以处理复杂的信息从而提高用户的工作效率,减少失误。所以本基于Vue和微信小程序的校园自助打印系统的开发非常有意义,本系统里的信......
  • Raft协议深度解析:RocketMQ中基于DLedger的日志主从复制
    本文所涉及的注释源码:bigcoder84/dledgerRaft协议主要包含两个部分:Leader选举和日志复制。前面我们在Raft协议深度解析:RocketMQ中的自动Leader选举与故障转移一文中已经详细介绍了DLedger如何实现Leader选举的,而本文主要聚焦于Leader选举完成后的日志复制的过程。一.Rock......
  • 简单的扫雷——基于C语言的控制台小游戏
    前言:  “将大象装进冰箱要几步?--打开冰箱,把大象放进去,关上冰箱。”  同样的,该扫雷游戏的编写过程也只需三步:逻辑梳理-代码实现-运行调试。本文将使用C语言来一步步剖析并完成扫雷这一案例。一.扫雷的游戏逻辑  该扫雷的游戏逻辑为:  1.生成棋盘,并布置数个......
  • redis的使用场景-热点数据缓存
    1.什么是缓存?把一些经常访问的数据放入缓存中,减少访问数据库的频率,减少数据库的压力,从而提高程序的性能。【内存中存储】2.缓存的原理通过上图可以看出程序首先访问缓存,如果缓存中有访问的数据会直接方会给客户端,不需要访问数据库,如果缓存中没有需要的数据则访问数据库,命中......
  • 基于LSTM的贵州茅台股票价格走势分析及预测模型研究【股票可换】
    文章目录==有需要本项目的代码或文档以及全部资源,或者部署调试可以私信博主==项目介绍引言研究背景国内外研究现状研究目的研究意义相关技术理论介绍数据采集数据分析与可视化预测模型搭建与结果评估每文一语有需要本项目的代码或文档以及全部资源,或者部署调试可......
  • Python毕业设计基于Django的网上购物销售系统(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录一、项目介绍二、主要使用技术三、研究内容四、核心代码五、文章目录一、项目介绍随着互联网技术的不断发展和普及,电子商务行业迅速崛起。越来越多的消费者选择在线购物,享受便捷、快速的购物体验。因此,开发一款基于Python的购物......
  • python毕业设计基于Django的电子书阅读系统的设计与实现 爬虫+大屏可视化
    文末获取资源,收藏关注不迷路文章目录一、项目介绍二、主要使用技术三、研究内容+四、核心代码五、文章目录一、项目介绍随着互联网的普及和移动设备的广泛应用,人们获取信息和阅读的方式发生了巨大变化。传统的纸质书籍阅读方式虽然经典,但存在携带不便、更新速度慢等......
  • Pyhton毕业设计基于django的旅游管理系统景点酒店订票和特产购物
    文末获取资源,收藏关注不迷路文章目录一、项目介绍亮点:景点和酒店订票,特色购物商城,在线地图功能二、主要使用技术三、研究内容四、核心代码五、文章目录一、项目介绍随着经济的快速发展和人民生活水平的提高,旅游业在全球范围内迅速发展,成为推动经济增长的重要力量。......
  • 基于python的出租车管理网站的设计与实现【源码+文档+PPT】
    ......
  • YOLOv8-seg——基于自定义数据集训练图像分割模型
    目录一、制作分割数据集1标注2json文件转txt文件3数据集划分二、训练图像分割模型1环境搭建2训练网络3预测三、训练结果解读一.制作分割数据集1标注运用labelme软件进行手动标注,得到数据的json格式标注文件。*注意区别于labelimg软件,labelimg软件对每个......