【笔记】使用redis作为分布式锁,手动版

//使用redis作为分布式锁
    public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock() {
        //TODO 【重要】实际就关心两个问题:1、原子加锁,保证过期时间;2、原子解锁
        String uuid = UUID.randomUUID().toString();
        //1、占分布式锁,去redis占坑 SETNXEX
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);
        if (lock) {
            System.out.println("成功获取分布式锁.....");
            //加锁成功执行业务
            //TODO 抛出问题:若执行业务时出错,没有解锁怎么办?
            // 答:加try catch finally解锁。
            // 那又有一个问题,执行业务时断电怎么办?
            // 答:给锁设置一个过期时间,必须和加锁是同步的,原子的。防止在拿到锁在执行业务前突然断电
            Map<String, List<Catelog2Vo>> dataFromDb = null;
            try {
                dataFromDb = getDataFromDb();
            }finally {
                //lua脚本
                String script = "if redis call('get',KEYS[1]) == ARGV[1] then return redis call('del',KEYS[1]) else return 0 end";
                //删锁
                stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),/*这里的Long表示返回值的类型,1-删除成功 0-删除不成功*/
                        Arrays.asList("lock"), uuid);//这里传uuid,是删除对比是不是自己的锁
            }
            //执行了业务要解锁
            //TODO 问题:业务超时,redis早就把锁释放了。现在加锁是其他线程的锁,现在执行删锁岂不是把别人的锁删掉?!
            //TODO 答:上锁时的值采用uuid。业务超时的话,设置锁过期时间长一点,300s。业务总不能超过300s吧!!
            //String lockValue = stringRedisTemplate.opsForValue().get("lock");
            //TODO IO时长问题:在获取lockValue进行IO的时候,返回锁的值给我们的时候,假如返回给我们需要0.5s,在0.3s时锁刚好过期,redis咔咔地帮我们把锁删掉,
            // 这个时候又有其他线程进来了加上了锁。那待获取值后再删锁,岂不又删了别人的锁?!
            // 答:用lua脚本执行删锁,保证原子性
            /*if (lockValue.equals(uuid)) {
                //删自己的锁,以uuid作为区分
                stringRedisTemplate.delete("lock");
            }*/
            return dataFromDb;
        } else {
            //加锁失败,100ms后重试
            System.out.println("获取分布式锁失败..正在重试....");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
            return getCatalogJsonFromDbWithRedisLock();//自旋
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值