redis分布式锁实现

发布时间 2023-06-26 23:24:11作者: DuX1ao
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

   //有死锁问题,设置锁的过期时间防止死锁
    public void incr() {
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "1111");	//setnx,只有key不存在才能设置成功
        if (lock) {
            String num = redisTemplate.opsForValue().get("num");
            Integer intNum = Integer.valueOf(num);
            intNum = intNum + 1;
            redisTemplate.opsForValue().set("num",intNum.toString());
            redisTemplate.delete("lock");
        }else {
            incr();
        }
public void incr() {
    //设置过期时间后出现了锁不住、删除别人锁的问题
    //保证加锁和设置锁时间原子性
    Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "1111",30, TimeUnit.SECONDS);
    if (lock) {
        String num = redisTemplate.opsForValue().get("num");
        Integer intNum = Integer.valueOf(num);
        intNum = intNum + 1;
        redisTemplate.opsForValue().set("num",intNum.toString());
        redisTemplate.delete("lock");
    }else {
        incr();
    }
    public void incr() {

        //给当前线程设置一个标识,在删除锁的时候,判断一下这把锁是否是自己的,锁不住问题没有解决
        String uuid = UUID.randomUUID().toString();
        //保证加锁和设置锁时间原子性
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 30, TimeUnit.SECONDS);
        if (lock) {
            String num = redisTemplate.opsForValue().get("num");
            Integer intNum = Integer.valueOf(num);
            intNum = intNum + 1;
            redisTemplate.opsForValue().set("num", intNum.toString());

            //使用lua表达式确保拿比删操作的原子性
            String luaString = "if redis.call('get',KEYS[1]) == ARGV[1] " +
                    "then " +
                    "return redis.call('del',KEYS[1]) " +
                    "else " +
                    "   return 0 " +
                    "end";
            redisTemplate.execute(new DefaultRedisScript<Long>(luaString, Long.class), Arrays.asList("lock"), uuid);
/*            String redisUuid = redisTemplate.opsForValue().get("lock");
            if(uuid.equals(redisUuid)){
                redisTemplate.delete("lock");
            }*/
        } else {
            incr();
        }
    }

使用Redission解决锁不住的问题

如果没有添加过期时间,默认锁时间是30s,且每到20s,会再次续期成30s,直到释放锁,或者是出现宕机 ,出现异常, 为止

分布式锁面试回答思路

1、介绍单体锁
2、引入分布式锁 手写分布式锁 遇见的问题 解决这些问题
3、我们工作中使用的是redisson,引出看门狗这个名词,总结源码
4、我们在项目中如何使用

Redission源码

1、抢锁的时候,以看门狗时间作为锁失效时间,每隔 30s (看门狗时间)/3 = 10s 再续约成30s
2、如果你设置了时间,就以你设置的时间作为锁失效时间,还不会续期