简易的Redis分布式锁
import cn.decentchina.kentucky.common.enums.ErrorCodeEnum;
import cn.decentchina.kentucky.common.exceptions.ErrorCodeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.util.Assert;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class RedisLockUtil {
private static final String REDIS_LOCK = "REDIS_LOCK_";
private static final String DEFAULT_MESSAGE = "未获得资源";
private static final Integer EXPIRE_TIME = 300;
private static final Integer SLEEP_TIME = 50;
private static final Integer CYCLES = 10;
@SuppressWarnings("all")
@Resource(name = "redisTemplate")
private ValueOperations<String, String> lockOperations;
public void lock(String key, String value) {
lock(key, value, EXPIRE_TIME, null);
}
public void lock(String key, String value, String message) {
lock(key, value, EXPIRE_TIME, message);
}
public void lock(String key, String value, Integer timeout, String message) {
Assert.isTrue(StringUtils.isNotBlank(key), "资源锁Key不能为空");
Assert.isTrue(StringUtils.isNotBlank(value), "资源锁Value不能为空");
int cycles = CYCLES;
while (!tryLock(key, value, timeout)) {
if (0 == (cycles--)) {
log.error("尝试获取锁失败 key: {}, value: {}", key, value);
throw new ErrorCodeException(ErrorCodeEnum.NO, StringUtils.isBlank(message) ? DEFAULT_MESSAGE : message);
}
try {
TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
} catch (Exception e) {
log.error("尝试获取锁异常", e);
}
}
}
public void unLock(String key, String value) {
Assert.isTrue(StringUtils.isNotBlank(key), "资源锁Key不能为空");
Assert.isTrue(StringUtils.isNotBlank(value), "资源锁Value不能为空");
key = REDIS_LOCK + key;
if (StringUtils.equals(value, lockOperations.get(key))) {
lockOperations.getOperations().delete(key);
}
}
private boolean tryLock(String key, String value, Integer timeout) {
Boolean result = lockOperations.setIfAbsent(REDIS_LOCK + key, value, timeout, TimeUnit.SECONDS);
return result != null && result;
}
}