欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > redis学习(015 实战:黑马点评:分布式锁)

redis学习(015 实战:黑马点评:分布式锁)

2025/8/12 15:51:58 来源:https://blog.csdn.net/wang_book/article/details/142364423  浏览:    关键词:redis学习(015 实战:黑马点评:分布式锁)

黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目

总时长 42:48:00 共175P

此文章包含第56p-第p63的内容


文章目录

    • 分布式锁介绍
      • 分布式锁的满足条件
    • 基于redis的分布式锁
      • 获取锁
      • 释放锁
    • 编写代码
      • 创建一个接口
      • 定义一个类 实现这个接口
        • 获取锁
        • 释放锁
      • 测试
        • 原来的代码
        • 修改后的代码
        • 开始测试,测试多个jvm的情况
      • 分布式锁误删问题
        • 改造代码
        • 开始测试
    • 原子性
      • 使用lua命令
      • 不带参数的写法
      • 带参数的写法
      • 业务流程
      • 编写脚本java代码
    • 总结

分布式锁介绍

在这里插入图片描述

不使用分布式锁的情况
在这里插入图片描述
使用分布式锁的情况
在这里插入图片描述
在这里插入图片描述

分布式锁的满足条件

这里一些可以满足也可以不满足的功能,如: 是否满足可重用性、是公平锁还是非公平锁、是阻塞的还是非阻塞的等

在这里插入图片描述
在这里插入图片描述

基于redis的分布式锁

获取锁

在这里插入图片描述
只有第一个成功了
在这里插入图片描述

释放锁

在这里插入图片描述
在这里插入图片描述
如果服务挂了,这里无法释放锁,就会产生死锁
这时候我们需要添加过期时间来阻止此类情况发生

在这里插入图片描述
在这里插入图片描述
这里要确保setnx 锁 和加过期时间保持原子性,要不然杠添加了锁,还没加过期时间就宕机了就完了,
所以我们使用一个命令来执行

SET 锁 值(线程名) NX EX 10
在这里插入图片描述

在这里插入图片描述
10秒内无法添加
在这里插入图片描述

过期之后又可以添加了
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

编写代码

在这里插入图片描述

在这里插入图片描述

创建一个接口

在这里插入图片描述

定义一个类 实现这个接口

在这里插入图片描述

在这里插入图片描述
定义锁的名称 前缀 等信息
在这里插入图片描述
定义一个构造函数 让其传入这两个值
在这里插入图片描述

调用redisTemplate的setnx方法 即 setIfAbsent()方法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

担心产生null 这里使用Boolean.TRUE.equals方法 只有true时返回true 其他时候是false
也可以使用hutool的方法实现

获取锁

在这里插入图片描述

释放锁

在这里插入图片描述

测试

原来的代码

在这里插入图片描述

修改后的代码

在这里插入图片描述
创建锁对象 使用的name我们是 业务:用户ID 这样锁的范围很小
在这里插入图片描述
因为这是自己写的工具类,需要实现复用,如果要注入就不能在别的地方用了,所以我们使用传入stringTedisTemolate的方式

也可以设置用户id+优惠卷id拼接

在这里插入图片描述
在这里插入图片描述

开始测试,测试多个jvm的情况

用postman发送两个请求
在这里插入图片描述

第一个是lock为true
在这里插入图片描述

第二个是lock为false
在这里插入图片描述

redis存到的数据
在这里插入图片描述

分布式锁误删问题

如果业务阻塞时间太久 超过了过期时间 直接释放锁了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这时候线程1把线程2的锁释放了 这时候线程2还没完成,线程3就进来了
在这里插入图片描述
在这里插入图片描述
这样就导致线程安全问题

应该在释放锁的时候判断一下是不是自己这个线程的锁 别把别人的锁给开了
在这里插入图片描述

在这里插入图片描述

改造代码

在这里插入图片描述
在这里插入图片描述
直接使用线程id的时候 集群情况下会出现冲突 这里我们加上uuid

ps:这里的uuid使用static final声明,这个uuid前缀一直不变,这样相当于这个uuid代表了本次启动后 这个jvm的一个唯一值
在这里插入图片描述

修改释放代码
在这里插入图片描述

开始测试

tomcat1 获取锁 然后阻塞住 然后手动删除模拟过期
在这里插入图片描述

在这里插入图片描述

让tomcat2执行,也获取到了锁
在这里插入图片描述
让tomcat1释放锁 ,可以看到两个id不一样
在这里插入图片描述

在这里插入图片描述

tomcat2释放锁
在这里插入图片描述
锁被删除
在这里插入图片描述
在这里插入图片描述

原子性

在一些极端条件下 还是存在问题
在这里插入图片描述
如果jvm垃圾回收的时间特别长 阻塞的时间超过了线程锁的过期时间

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

所以判断锁和释放锁的两个命令必须是原子性操作才可以
在这里插入图片描述

使用lua命令

在这里插入图片描述
可以使用lua脚本保持命令的原子性
在这里插入图片描述
可以进入网站学习lua脚本命令
在这里插入图片描述

在这里插入图片描述

不带参数的写法

后面的0代表本次没有参数进来 是个写死的脚本
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

带参数的写法

切记 lua的数组下标是从1开始的不是0
在这里插入图片描述
这里的1代表key的数量
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

业务流程

在这里插入图片描述
用vscode新建一个文件 然后 选择编程语言 这样就可以选择lua语言 这样有高亮提示(idea也有lua插件)
在这里插入图片描述

在这里插入图片描述

判断当前的锁id是否相同,相同就删除 的lua脚本
在这里插入图片描述

简化脚本
在这里插入图片描述

在这里插入图片描述

编写脚本java代码

在这里插入图片描述

我们创建一个lua脚本文件 (创文件.lua后缀,idea会提示安装插件)
在这里插入图片描述

这里注意,虽然返回值只是0和1,但是也要用Long类型接值。脚本执行不支持接受Integer类型

使用 ClassPathResource()方法找到classpath下的文件
在这里插入图片描述
我们的文件放在 resources文件夹下 就直接就是classpath

在这里插入图片描述
代码如下· 因为我们放到了static块下 因此这个类加载的时候就会去访问unlock.lua,这个脚本就被初始化了
在这里插入图片描述

Collections.singletonList单元素数组
在这里插入图片描述
这时已经将代码变成了一行 就不会出现原子性问题了
在这里插入图片描述

总结

在这里插入图片描述


版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词