流程图:
代码
public class LockRedis {
private static final Logger logger = LoggerFactory.getLogger(LockRedis.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private ThreadLocal<String> lockFlag = new ThreadLocal<>();
/**
* 释放锁的原子操作lua脚本
*/
public static final String UNLOCK_LUA;
/**
* 默认的锁超时时间:15秒
*/
private Long default_expire = 15000L;
/**
* 默认的重试次数 100次
*/
private Integer default_retryTimes = 100;
/**
* 默认的重试间隔时间:0.3秒
*/
private Long default_sleepMillis = 300L;
static {
StringBuilder sb = new StringBuilder();
sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
sb.append("then ");
sb.append(" return redis.call(\"del\",KEYS[1]) ");
sb.append("else ");
sb.append(" return 0 ");
sb.append("end ");
UNLOCK_LUA = sb.toString();
}
/**
* 加锁并自定义过期时间
* @param key
* @param default_expire
* @return
*/
public boolean lock(String key, long default_expire) {
return lock(key, default_expire, null, null);
}
/**
* 加锁
* @param key
* @return
*/
public boolean lock(String key) {
return lock(key, null, null, null);
}
/**
* @param key 锁住的key
* @param expire 锁存在时间
* @param retryTimes 重试次数
* @param sleepMillis 重试间隔
* @return
*/
public boolean lock(String key, Long expire, Integer retryTimes, Long sleepMillis) {
expire = expire == null || expire < 0 ? default_expire : expire;
retryTimes = retryTimes == null || retryTimes <= 0 ? default_retryTimes : retryTimes;
sleepMillis = sleepMillis == null || sleepMillis <= 0 ? default_sleepMillis : sleepMillis;
boolean result = false;
do {
result = setRedis(key, expire);
if (!result) {
try {
Thread.sleep(sleepMillis);
} catch (InterruptedException e) {
logger.error("休眠线程异常", e);
return false;
}
}
} while ((!result) && retryTimes-- > 0);
return result;
}
private boolean setRedis(final String key, final long expire) {
try {
final String uuid = UUID.randomUUID().toString();
lockFlag.set(uuid);
final Boolean result = redisTemplate.execute((RedisCallback<Boolean>) redisConnection ->
redisConnection.set(key.getBytes(), uuid.getBytes(), Expiration.from(expire, TimeUnit.MILLISECONDS),
RedisStringCommands.SetOption.SET_IF_ABSENT)
);
return result;
} catch (Exception e) {
logger.error("设置redis锁异常", e);
}
return false;
}
/**
* 释放锁
* @param key
* @return
*/
public boolean unLock(final String key) {
try {
final Boolean result = redisTemplate.execute((RedisCallback<Boolean>) redisConnection ->
redisConnection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN, 1, key.getBytes(), lockFlag.get().getBytes()));
return result;
} catch (Exception e) {
logger.error("释放redis锁异常", e);
} finally {
lockFlag.remove();
}
return false;
}
}