分布式锁的原子性问题

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
相关推荐
Dylan~~~1 天前
深度解析Cassandra:分布式数据库的王者之路
数据库·分布式
传感器与混合集成电路1 天前
面向储气库注采井的分布式光纤监测技术
分布式
ZTLJQ1 天前
任务调度的艺术:Python分布式任务系统完全解析
开发语言·分布式·python
被摘下的星星1 天前
Hadoop伪分布式集群搭建实验原理概要
大数据·hadoop·分布式
无名-CODING1 天前
Java 爬虫高级技术:反反爬策略与分布式爬虫实战
java·分布式·爬虫
8Qi81 天前
Redis哨兵模式(Sentinel)深度解析
java·数据库·redis·分布式·缓存·sentinel
爱学习的程序媛1 天前
JWT签发全指南:从原理到安全实践
分布式·安全·web安全·安全架构·jwt签发·无状态认证
wanhengidc1 天前
徐州服务器租用的优势
大数据·运维·服务器·分布式·智能手机
wanzehongsheng1 天前
分布式光伏电站的技术优势与智能运维实践:以WZ HELIO²双轴跟踪系统为例
运维·分布式
爱浦路 IPLOOK1 天前
分布式UPF架构:让低时延与大带宽不再是难题
分布式·架构