Redis实现分布式锁

60 阅读1分钟

分布式加锁

Redis加锁如果使用setnx + expire不能保证其原子性,若setnx操作完成时Redis宕机,过期时间未设置成功则会导致死锁。

private static final String LOCK_SUCCESS = "OK";

/**
 * 分布式加锁
 *
 * @param num
 * @param key
 * @param requestId
 * @return
 */
public static Boolean getLock(int num, String key, String requestId) {
    Jedis jedis = null;
    try {
        jedis = getPool(num).getResource();
        String result = jedis.set(key, requestId, SetParams.setParams().nx().ex(30));
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
    } catch (Exception e) {
        logger.error("lock error ", e);
    } finally {
        if (jedis != null) {
            jedis.close();
        }
    }
    return false;
}

Redis使用lua脚本释放锁

private static final Long RELEASE_SUCCESS = 1L;

/**
 * 手动释放锁
 *
 * @param key
 * @param requestId
 * @return
 */
public static Boolean releaseLock(String key, String requestId) {
    Jedis jedis = null;
    try {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
    } catch (Exception e) {
        logger.error("releaseLock error ", e);
    } finally {
        if (jedis != null) {
            jedis.close();
        }
    }
    return false;
}