redis分布式锁

分布式锁

通过2个原子性的命令setnx getset
还有
expire 设有效期
del 删除

第一版分布式锁

版本1
   
    public void 分布式锁版本1(){
      
        Long setnxResult = RedisShardedPoolUtil.setnx(key, 现在时间);
        //mark 如果允许到这 tomcat重启了 锁还没有加期限  这个锁就永远不会被释放了 没人可以再得到锁了
        //如果是正常关闭 delLock能解决
        if(setnxResult != null && setnxResult.intValue() == 1){
            //如果返回值是1,代表设置成功,获取锁 closeOrder还会设定过期时间 完成后删除锁
          RedisShardedPoolUtil.expire(key,50);//有效期 50秒,防止死锁

          //业务执行
         
           RedisShardedPoolUtil.del(key);  //释放锁   
        }
      
    }

但是如果得到锁,还没设有效期 tomcat就重启了,这个锁就永远没人能得到了

Redis 2.8 版本中作者加入了 set 指令的扩展参数,使得 setnx 和 expire 指令可以一起执行
set lock:codehole true ex 5 nx

为了防止这种情况

   //tomcat 正常关闭前会调用
    @PreDestroy
    public void delLock(){
        //释放锁
        RedisShardedPoolUtil.del(key);

    }

虽然可以@PreDestroy让tomcat关闭前调用,但是tomcat不一定是正常关闭,如果要好多锁需要释放,tomcat就会很慢

第二版分布式锁

第二版

第二版就是利用了setnx进去的过期时间,如果这个值过期了 也算拿到锁

   public void 第二版() {
        Long setnxResult = RedisShardedPoolUtil.setnx(key, 现在时间);

        //顺利拿到锁
        if (setnxResult != null && setnxResult.intValue() == 1) {
           
             //业务 

           RedisShardedPoolUtil.del(key);  //释放锁   
            return;
        }

        //未获取到锁,继续判断,判断时间戳,看是否可以重置并获取到锁
        String oldValue = RedisShardedPoolUtil.get(key);

        //再看这个锁没有了,或者那个锁超时了
        if (oldValue != null && System.currentTimeMillis() > Long.parseLong(oldValue)) {          

            //再次用当前时间戳getset。
            String getSetResult = RedisShardedPoolUtil.getSet(key, 现在时间);

           //当key没有旧值时,即key不存在时,返回nil ->获取锁
            // 旧值就是我们刚才看到的过期的那个 ->获取锁
            if (getSetResult == null ||  StringUtils.equals(oldValue, getSetResult)) {
              
               //业务

                RedisShardedPoolUtil.del(key);  //释放锁   
                return;
            }
        }

       //没有获取到分布式锁:
    }

第三版分布式锁 用Redssion

    @Autowired
    private RedissonManager redissonManager;
//    @Scheduled(cron="0 */1 * * * ?")
    public void 第三版(){
        RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        boolean getLock = false;
        try {
            //等待0秒(只能填0),最多持有锁50秒
            getLock = lock.tryLock(0, 50, TimeUnit.SECONDS);
            if(getLock){
                log.info("Redisson获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());

              // 业务代码

            }else{
                log.info("Redisson没有获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            log.error("Redisson分布式锁获取异常",e);
        } finally {
            //如果拿到锁了就要释放
            if(getLock){
                lock.unlock();
                log.info("Redisson分布式锁释放锁");
            }
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 分布式锁的解决方式 基于数据库表做乐观锁,用于分布式锁。(适用于小并发) 使用memcached的add()方法,...
    xiaolyuh阅读 15,609评论 6 17
  • 我们知道分布式锁的特性是排他、避免死锁、高可用。分布式锁的实现可以通过数据库的乐观锁(通过版本号)或者悲观锁(通过...
    Java大生阅读 429评论 0 0
  • 我们知道分布式锁的特性是排他、避免死锁、高可用。分布式锁的实现可以通过数据库的乐观锁(通过版本号)或者悲观锁(通过...
    cmazxiaoma阅读 34,079评论 7 29
  • 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper...
    朦胧蜜桃阅读 503评论 1 0
  • 浅相逢,几时重?时光记忆,又似薄无一物;时光还在,你确和我们散了;以后再说想静静,想起的都是曾经;静静是谁,问问来...
    心灵烟火阅读 186评论 0 0