分布式锁中的问题
分布式锁中我们设置的过期时间:
如果有一个线程获取锁之后在进行操作时,到达了锁的过期时间,之后就会有别的线程获得锁,如果这时,第一个线程执行完成后释放锁,就会将第二个锁的线程删除
针对这个情况如何改进:
- 在获取锁时存入线程标示(可以用UUID)
- 在释放锁时先获取锁中的线程标示,判断是否与当前线程标识一致
- 如果一致则释放锁
- 如果不一致则不释放锁
改进分布式锁添加释放锁的判断
public class SimpleRedisLock implements ILock{
private String name;
private StringRedisTemplate stringRedisTemplate;
public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
this.name = name;
this.stringRedisTemplate = stringRedisTemplate;
}
private static final String key_prefix="lock:";
private static final String id_prefix= UUID.randomUUID().toString()+"-";
@Override
public boolean tryLock(long timeoutSec) {
//获取线程的标识
String threadId= id_prefix+Thread.currentThread().getId();
Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(key_prefix + name, threadId, timeoutSec, TimeUnit.SECONDS);
//自动拆箱的返回
return Boolean.TRUE.equals(aBoolean);
}
@Override
public void unlock() {
//获取线程标识
String threadid = id_prefix + Thread.currentThread().getId();
//获取锁中的标识
String s = stringRedisTemplate.opsForValue().get(key_prefix + name);
//判断标识是否一致
if(threadid.equals(s)) {
//释放锁
stringRedisTemplate.delete(key_prefix+name);
}
}
}
上述我们做了修改进行判断,但是还存在一种极端情况,当线程操作完毕需要释放锁的时候,这个时候已经判断完毕,但是由于比如说垃圾回收等问题对线程的释放操作进行阻塞,这个时候如果超过等待时间,这是还是会出现上述问题,在阻塞结束之后,会删除其他线程的锁
要彻底避免这种情况的发生,需要将判断锁标识的动作与释放锁标识的动作进行原子性操作,此时就会用到Lua脚本
Lua脚本
Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性,Lua脚本时一种编程语言
地址:https://www.runoob.com/lua/lua-tutorial.html
编写Lua脚本
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by LENOVO.
--- DateTime: 2024/4/26 19:01
---比较线程标识与锁中的标识是否一致
if(redis.call('get',KEY[1]) == ARGV[1]) then
--- 释放锁资源
return redis.call('del',KEY[1])
end
return 0
调用Lua脚本:文章来源:https://www.toymoban.com/news/detail-861130.html
@Override
public void unlock() {
//调用lua脚本
stringRedisTemplate.execute(
UNLOCK_SCRIPT,
Collections.singletonList(key_prefix+name),
id_prefix+Thread.currentThread().getId());
}
其中的UNLOCK_SCRIPT
是脚本对象,需要提前进行定义文章来源地址https://www.toymoban.com/news/detail-861130.html
//设置脚本对象
private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
static{
UNLOCK_SCRIPT =new DefaultRedisScript<>();
UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
UNLOCK_SCRIPT.setResultType(Long.class);
}
到了这里,关于【Redis 开发】分布式锁中的常见问题和Lua脚本的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!