使用Redis实现简单的分布式锁-SETNX

2周前 (09-10) wang 技术杂谈 0评论 未收录 18℃ 浏览数:16

SETNX命令简介

将 key 的值设为 value,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是SET if Not eXists的简写。

返回值

返回整数,具体为
- 1,当 key 的值被设置
- 0,当 key 的值没被设置

1、尝试setnx,如果返回1则获取锁
2、返回0,说明没有获取到锁,检查是否超时
  2.1、锁已经超时 使用getSet尝试获取锁
   2.1.1 返回成功,返回的旧时间等于保存的旧时间,则是本线程获取到的锁,返回成功
   2.1.2 返回成功,返回的旧时间不等于保存的旧时间,不是本线程获取的锁,返回失败,这里可能会更新其他线程设置的超时时间,可以忽略不计
  2.2、锁没有超时,while循环获取
private boolean lock(String key,long timeout){
        long current = System.currentTimeMillis();
        long newExpire = current + timeout;
        try {
            Result<Long> result = dailyLotteryCacheWrapper.
                      getMoguCacheFactory().setnx(key,String.valueOf(newExpire));
            if(result != null && result.isSuccess() && result.getValue() != null){
                if(result.getValue().intValue() == 1){
                    //1.直接获取到锁
                    return true;
                }else {
                    //2.没有获取到锁,检查锁是否超时
                    String value = dailyLotteryCacheWrapper.get(key);
                    logger.info("expire:{} current:{}",value,current);
                    if(!StringUtils.isEmpty(value)){
                        long oldExpire = Long.valueOf(value);
                        if(oldExpire < current){
                            //2.1锁已经超时
                            Result<String> oldResult = 
                              dailyLotteryCacheWrapper.getMoguCacheFactory().
                              getSet(key,String.valueOf(newExpire));
                            if (oldResult != null && oldResult.isSuccess()){
                                if(StringUtils.isEmpty(oldResult.getValue()) || 
                                oldResultgetValue().equals(String.valueOf(oldExpire))){
                                    //锁超时,本线程强行获取到锁
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("lock jackpot failed,e:{}",e);
        }

        return false;
    }


    public boolean lock(String key){
        int i = 0;
        while (true){
            i++;
            if (i > 100){
                logger.warn("try to get locker count:{}",i);
            }
            if (this.lock(key,TIMEOUT)){
                return true;
            }
        }
    }
博主

Just do it. Now or never.

相关推荐

嗨、骚年、快来消灭0回复。