redis 分布式锁(单机完美版本)

众所周知,redis可以实现分布式锁,如果考虑故障转移,需要用redlock算法的支持。如果不考虑,常用的简单实现如下所示:

  /**
     * 如果锁可用,则获取锁,并立即返回value值。如果锁不可用,则此方法将立即返回null。
     * 不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)
     * @param key redis的key值
     * @param keyExpireSecond redis key的有效期
     * @return 如果获取了锁,则返回 value 否则返回 null。
     */
    public String tryLock(String key, int keyExpireSecond) {
        if (Strings.isNullOrEmpty(key) || keyExpireSecond < 0) {
            throw new IllegalArgumentException("param is illegal");
        }
        String value=fetchLockValue();
        if ("ok".equalsIgnoreCase(jedisCluster.set(key, value,"nx","ex",keyExpireSecond ))){
            return value;
        }
        return  null;
    }

    /**
     * 阻塞直到获取锁为止
     * 不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)
     * @param key
     * @param keyExpireSecond
     * @return
     */
    public String lock(String key, int keyExpireSecond){
        String value=fetchLockValue();
        do {
            if ("ok".equalsIgnoreCase(jedisCluster.set(key, value, "NX", "EX", keyExpireSecond))) {
                logger.info("Redis Lock key :{} ,value{}",key,value);
                return value;
            }
            logger.info("Redis lock failure,waiting try next");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.error("The lock operation is interrupted",e);
            }
        } while (true);
    }

    /**
     * 解锁操作,只在客户端传入的值和键的口令串相匹配时,才对键进行删除
     * 第一个参数命令,第二个参数个数,第三个开始是key,剩下的ARGV
     * > eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
     1) "key1"
     2) "key2"
     3) "first"
     4) "second"
     * @param key
     * @param value
     * @return
     */
    public boolean unLock(String key, String value) {
        Long RELEASE_SUCCESS = 1L;
        try {

            String command = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            if (RELEASE_SUCCESS.equals(jedisCluster.eval(command, Collections.singletonList(key), Collections.singletonList(value)))) {
                return true;
            }
        } catch (Exception e) {
            logger.error("Failed to unlock {}",key);
        }
        return false;
    }
    /**
     * 生成加锁的唯一字符串
     *
     * @return 唯一字符串
     */
    private String fetchLockValue() {
        return UUID.randomUUID().toString() + "_" + String.valueOf(System.currentTimeMillis());
    }

你可能感兴趣的:(java技术)