JAVA 基于Redis的分布式锁

分布式锁一般有三种实现方式:

  • 数据库乐观锁
  • 基于ZooKeeper的分布式锁
  • 基于Redis的分布式锁

这里主要记录下基于Redis的分布式锁

Redis加锁

springboot2.1以后的版本可以直接使用redisTemplate提供的setIfAbsent方法进行加锁 相当于使用redis命令:SET key value [EX seconds] [PX millisecounds] [NX|XX]

redisTemplate.opsForValue().setIfAbsent(key,value,time,TimeUnit)
  • 为什么是set命令而不是setNx命令?

因为setNx 无法设置key过期时间 需要通过expire来为key设置过期时间,意味着加锁是两条命令,不满足原子性。

  • 锁的过期时间设置多少合适,是否可以不设置?

锁的过期时间一定是要有的,不然留着过年么?过期时间根据具体的业务逻辑来设置,但是一定要大于代码执行的时间。例如:

	//加锁  锁的过期时间为5秒
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("111", "11", 5, TimeUnit.SECONDS);
        if(lock){
            System.out.println("业务逻辑执行在0-8秒范围内");
        }

这个时候肯定是不合适的。

Redis解锁

  1. 加锁之后,一定要保证锁的释放,所以通常是在finally代码块里面释放锁。
  2. 获取到锁才释放锁,没有获取到,不要去释放锁,避免释放其他客户端加的锁。
  3. 释放锁的时候可以判断锁的持有者是否是自己,是自己的才进行释放。(2和3至少要遵循一个,这样才能避免误释放锁)

解锁方式一:

redisTemplate.delete(key)

解锁方式二:使用lua脚本

if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

完整的加锁解锁代码如下:

@Autowired
    RedisTemplate redisTemplate;

    @Test
    public void testLock() throws UnknownHostException {
        String key = "lockTest";
        InetAddress ia = InetAddress.getLocalHost();
        String value = ia.toString();
        //加锁  锁的过期时间为20秒
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, value, 20, TimeUnit.SECONDS);
        if (!lock) {
            //未获取到锁,直接返回
            return;
        }
        try {
            System.out.println("业务逻辑执行在小于20秒范围内");
        } catch (Exception e) {
            System.out.println("业务错误信息");
        } finally {
            // 方式一 直接使用del
            redisTemplate.delete(key);
            // 方式二 使用lua脚本
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            RedisScript redisScript = new DefaultRedisScript(script);
            List<String> keys = new ArrayList<>();
            keys.add(key);
            redisTemplate.execute(redisScript, keys, value);
        }

    }
# redis 

标题:JAVA 基于Redis的分布式锁
作者:hjljy
地址:https://www.aliuying.com/articles/2021/03/05/1614931478736.html

评论

取消