public class LockHolder {
/**
* k:v -> lockKey:lockNode
*/
private static ThreadLocal<ConcurrentHashMap<String, String>> LOCKERS = ThreadLocal.withInitial(ConcurrentHashMap::new);
public static ConcurrentHashMap<String, String> get() {
return LOCKERS.get();
}
public static void set(ConcurrentHashMap<String, String> map) {
LOCKERS.set(map);
}
public static void remove() {
LOCKERS.remove();
}
}
public class RedisDistributedLock {
private RedisTemplate redisTemplate;
private long ttl = 60;//second
private static Logger log = LoggerFactory.getLogger(RedisDistributedLock.class);
public RedisDistributedLock(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public RedisDistributedLock(RedisTemplate redisTemplate, long ttl) {
this(redisTemplate);
this.ttl = ttl;
}
public boolean tryLock(String lockKey, Duration timeout) {
long start = Instant.now().toEpochMilli();
long end = start + timeout.toMillis();
String nodeId = LockHolder.get().get(lockKey);
if (nodeId == null) {
nodeId = UUID.randomUUID().toString();
}
while (System.currentTimeMillis() <= end) {
Boolean save = redisTemplate.opsForValue().setIfAbsent(lockKey, nodeId, Duration.ofSeconds(ttl));
if (null != save && save) {
LockHolder.get().put(lockKey, nodeId);
return true;
} else {
LockSupport.parkNanos(500 * 1000);
}
}
return false;
}
public boolean unlock(String lockKey) {
String nodeId = LockHolder.get().get(lockKey);
try {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
DefaultRedisScript<Boolean> holdScript = new DefaultRedisScript<>();
holdScript.setScriptText(script);
holdScript.setResultType(Boolean.class);
Boolean result = (Boolean) redisTemplate.execute(holdScript, Collections.singletonList(lockKey), nodeId);
boolean unlock = result.booleanValue();
if (unlock) {
LockHolder.get().remove(lockKey);
}
return true;
} catch (Exception e) {
log.info("unlock lock failed, lockKey:{}, nodeId:{}", lockKey, nodeId);
return false;
}
}
}
使用时