设计注意点
1.锁要有超时时间 setnx 加时间
2.锁要释放 finally
3.借助threadlocal避免线程错乱解锁
public class DistributedLockService {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "EX";
private static final Long RELEASE_SUCCESS = 1L;
static String RELEASE_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
@Autowired
private JedisFacade jedisFacade;
private final Logger logger = LoggerFactory.getLogger(DistributedLockService.class);
private ThreadLocal<String> tokenMap = new ThreadLocal<>();
public boolean tryAcquire(String key , Long timeOutSeconds){
String token = tokenMap.get();
if (StringUtils.isBlank(token)) {
token = UUID.randomUUID().toString().replaceAll("-","");
tokenMap.set(token);
}
String result = jedisFacade.set(key , token , SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, timeOutSeconds);
boolean flag = StringUtils.equalsIgnoreCase(LOCK_SUCCESS , result);
if(!flag){
String origToken = jedisFacade.get(key);
if (StringUtils.isBlank(origToken)) {
result = jedisFacade.set(key, token, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, timeOutSeconds);
if (StringUtils.equalsIgnoreCase(LOCK_SUCCESS , result)){
flag = true;
}
}else if(token.equals(origToken)){
flag = true;
}
}
return flag;
}
public boolean tryRelease(String distributeKey) {
String token = tokenMap.get();
String origToken = jedisFacade.get(distributeKey);
//如果为空 则返回解锁成功 可能是狗屎运-并不是自己完成解锁的
if(StringUtils.isBlank(origToken)){
logger.info("锁超时释放..");
return true;
}
//检查当前解锁的线程的合法性
if(StringUtils.isBlank(token) || !StringUtils.equals(origToken , token)){
return false;
}
Object result = jedisFacade.eval(RELEASE_SCRIPT , Collections.singletonList(distributeKey), Collections.singletonList(token));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}