基於redis的分佈式鎖實現【換毛名字】

設計注意點

1.鎖要有超時時間 setnx 加時間

2.鎖要釋放 finally

3.藉助threadlocal避免線程錯亂解鎖

 

public class DistributedLockService {

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "EX";

    private static final Long RELEASE_SUCCESS = 1L;

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

    @Autowired
    private JedisFacade jedisFacade;

    private final Logger logger = LoggerFactory.getLogger(DistributedLockService.class);

    private ThreadLocal<String> tokenMap = new ThreadLocal<>();

    public boolean tryAcquire(String key , Long timeOutSeconds){
        String token = tokenMap.get();
        if (StringUtils.isBlank(token)) {
            token = UUID.randomUUID().toString().replaceAll("-","");
            tokenMap.set(token);
        }
        String result = jedisFacade.set(key , token , SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, timeOutSeconds);
        boolean flag = StringUtils.equalsIgnoreCase(LOCK_SUCCESS , result);
        if(!flag){
            String origToken = jedisFacade.get(key);
            if (StringUtils.isBlank(origToken)) {
                result = jedisFacade.set(key, token, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, timeOutSeconds);
                if (StringUtils.equalsIgnoreCase(LOCK_SUCCESS , result)){
                    flag = true;
                }
            }else if(token.equals(origToken)){
                flag = true;
            }
        }
        return flag;
    }

    public boolean tryRelease(String distributeKey) {
        String token = tokenMap.get();
        String origToken = jedisFacade.get(distributeKey);
        //如果爲空 則返回解鎖成功 可能是狗屎運-並不是自己完成解鎖的
        if(StringUtils.isBlank(origToken)){
            logger.info("鎖超時釋放..");
            return true;
        }
        //檢查當前解鎖的線程的合法性
        if(StringUtils.isBlank(token) || !StringUtils.equals(origToken , token)){
            return false;
        }
        Object result = jedisFacade.eval(RELEASE_SCRIPT , Collections.singletonList(distributeKey), Collections.singletonList(token));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章