分布式锁的原子性问题

4.6 分布式锁的原子性问题

更为极端的误删逻辑说明:

线程1现在持有锁之后,在执行业务逻辑过程中,他正准备删除锁,而且已经走到了条件判断的过程中,比如他已经拿到了当前这把锁确实是属于他自己的,正准备删除锁,但是此时他的锁到期了,那么此时线程2进来,但是线程1他会接着往后执行,当他卡顿结束后,他直接就会执行删除锁那行代码,相当于条件判断并没有起到作用,这就是删锁时的原子性问题,之所以有这个问题,是因为线程1的拿锁,比锁,删锁,实际上并不是原子性的,我们要防止刚才的情况发生,

4.7 Lua脚本解决多条命令原子性问题

Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。Lua是一种编程语言,它的基本语法大家可以参考网站:https://www.runoob.com/lua/lua-tutorial.html,这里重点介绍Redis提供的调用函数,我们可以使用lua去操作redis,又能保证他的原子性,这样就可以实现拿锁比锁删锁是一个原子性动作了,作为Java程序员这一块并不作一个简单要求,并不需要大家过于精通,只需要知道他有什么作用即可。

这里重点介绍Redis提供的调用函数,语法如下:

lua 复制代码
redis.call('命令名称', 'key', '其它参数', ...)

例如,我们要执行set name jack,则脚本是这样:

lua 复制代码
# 执行 set name jack
redis.call('set', 'name', 'jack')

例如,我们要先执行set name Rose,再执行get name,则脚本如下:

lua 复制代码
# 先执行 set name jack
redis.call('set', 'name', 'Rose')
# 再执行 get name
local name = redis.call('get', 'name')
# 返回
return name

写好脚本以后,需要用Redis命令来调用脚本,调用脚本的常见命令如下:

例如,我们要执行 redis.call('set', 'name', 'jack') 这个脚本,语法如下:

如果脚本中的key、value不想写死,可以作为参数传递。key类型参数会放入KEYS数组,其它参数会放入ARGV数组,在脚本中可以从KEYS和ARGV数组获取这些参数:

接下来我们来回一下我们释放锁的逻辑:

释放锁的业务流程是这样的

​ 1、获取锁中的线程标示

​ 2、判断是否与指定的标示(当前线程标示)一致

​ 3、如果一致则释放锁(删除)

​ 4、如果不一致则什么都不做

如果用Lua脚本来表示则是这样的:

最终我们操作redis的拿锁比锁删锁的lua脚本就会变成这样

lua 复制代码
-- 这里的 KEYS[1] 就是锁的key,这里的ARGV[1] 就是当前线程标示
-- 获取锁中的标示,判断是否与当前线程标示一致
if (redis.call('GET', KEYS[1]) == ARGV[1]) then
  -- 一致,则删除锁
  return redis.call('DEL', KEYS[1])
end
-- 不一致,则直接返回
return 0
相关推荐
萧鼎3 小时前
Python pyzmq 库详解:从入门到高性能分布式通信
开发语言·分布式·python
卡拉叽里呱啦6 小时前
缓存-变更事件捕捉、更新策略、本地缓存和热key问题
分布式·后端·缓存
BD_Marathon8 小时前
Kafka文件存储机制
分布式·kafka
哈哈很哈哈9 小时前
Spark 运行流程核心组件(三)任务执行
大数据·分布式·spark
jakeswang15 小时前
应用缓存不止是Redis!——亿级流量系统架构设计系列
redis·分布式·后端·缓存
不久之17 小时前
大数据服务完全分布式部署- 其他组件(阿里云版)
分布式·阿里云·云计算
Direction_Wind18 小时前
粗粮厂的基于spark的通用olap之间的同步工具项目
大数据·分布式·spark
tan77º1 天前
【项目】分布式Json-RPC框架 - 项目介绍与前置知识准备
linux·网络·分布式·网络协议·tcp/ip·rpc·json
BYSJMG1 天前
计算机大数据毕业设计推荐:基于Hadoop+Spark的食物口味差异分析可视化系统【源码+文档+调试】
大数据·hadoop·分布式·python·spark·django·课程设计
Viking_bird1 天前
Apache Spark 3.2.0 开发测试环境部署指南
大数据·分布式·ajax·spark·apache