【 Lua脚本解决Redis多条命令原子性问题】-Redis学习笔记06

前言

Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。Lua是一种编程语言,它的基本语法大家可以参考网站: https://www.runoob.com/lua/lua-tutorial.html

问题分析

 public void unlock() {
        // 1.获取线程标识
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        // 2.获取锁中的标识
        String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
        // 3.判断线程标识和锁标识是否一样
        if (threadId.equals(id)) {
            stringRedisTemplate.delete(KEY_PREFIX + name);
        }
    }

上述代码中,线程1如果判断完线程标识和锁中的标识一致,进入了If判断中,在此时JVM进行GC垃圾回收,造成阻塞,如果在阻塞时间内,锁到了自动释放时间,被自动释放了,线程2拿到锁后,开始执行代码,此时,线程1的JVM垃圾回收结束,线程1此时就会将线程2的锁释放掉,造成了线程安全问题,解决此问题,就需要将判断和释放锁的动作放到一起执行。

Lua脚本

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

  1. 获取锁中的线程标示
  2. 判断是否与指定的标示(当前线程标示)一致
  3. 如果一致则释放锁(删除)
  4. 如果不一致则什么都不做
    如果用Lua脚本来表示则是这样的:
-- 这里的 KEYS[1] 就是锁的key,这里的ARGV[1] 就是当前线程标示
-- 获取锁中的标示,判断是否与当前线程标示一致
if(redis.call('GET',KEYS[1]==ARGV[1])) then 
    -- 一致 删除锁
    return redis.call('del',KEYS[1])
end
-- 不一致直接返回0
return 0

java执行Lua脚本

在resources下新建Lua脚本
新建Lua脚本
如果IDEA新建时候没有Lua File选项,则需要先安装Lua插件,安装过的忽略。
IDEA安装Lua插件
RedisTemplate调用Lua脚本的APIRedisTemplate调用Lua脚本的API

修改SimpleRedisLock类的 unlock方法

    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
    // 使用静态代码块,当类加载时候,就将Lua脚本加载进来,避免重复IO流,影响性能
    static {
        UNLOCK_SCRIPT=new DefaultRedisScript<>();
        // 设置脚本的位置
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        // 设置脚本的返回值
        UNLOCK_SCRIPT.setResultType(Long.class);
    }
 @Override
    public void unlock() {
      // 调用Lua脚本,释放锁
        stringRedisTemplate.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PREFIX + name),// Collections.singletonList()将单个元素转换成集合。
                ID_PREFIX + Thread.currentThread().getId()
        );
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值