分布式加锁
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;
}