定义锁对象
package com.tinet.clink.core.lock;
import java.io.Closeable;
import java.util.UUID;
public class RedisLock implements Closeable {
private String key;
private final UUID uuid;
private long lockTimeout;
private RedisLockService redisLockService;
public RedisLock(String key, UUID uuid, long lockTimeout, RedisLockService redisLockService) {
this.key = key;
this.uuid = uuid;
this.lockTimeout = lockTimeout;
this.redisLockService = redisLockService;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public UUID getUuid() {
return uuid;
}
public long getLockTimeout() {
return lockTimeout;
}
public void setLockTimeout(long lockTimeout) {
this.lockTimeout = lockTimeout;
}
@Override
public void close() {
this.redisLockService.unLock(this);
}
}
分布式锁服务
package com.tinet.clink.core.lock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import java.util.Collections;
import java.util.UUID;
public class RedisLockService {
private Logger logger = LoggerFactory.getLogger(getClass());
private static final long DEFAULT_LOCK_TIME_OUT = 3000;
private static final long DEFAULT_TRY_LOCK_TIME_OUT = 0;
private static final String LUA_SCRIPT_LOCK = "return redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) ";
private static final String LUA_SCRIPT_UNLOCK = "if (redis.call('GET', KEYS[1]) == ARGV[1]) then return redis" +
".call('DEL',KEYS[1]) else return 0 end";
private static RedisScript<String> scriptLock = new DefaultRedisScript<String>(LUA_SCRIPT_LOCK, String.class);
private static RedisScript<String> scriptUnlock = new DefaultRedisScript<String>(LUA_SCRIPT_UNLOCK, String.class);
private RedisTemplate<String, Object> redisTemplate;
public RedisLockService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public RedisLock lock(String key) {
return lock(key, DEFAULT_LOCK_TIME_OUT, DEFAULT_TRY_LOCK_TIME_OUT);
}
public RedisLock lock(String key, long lockTimeout) {
return lock(key, lockTimeout, DEFAULT_TRY_LOCK_TIME_OUT);
}
public RedisLock lock(String key, long lockTimeout, long tryLockTimeout) {
key = key + ".lock";
long timestamp = System.currentTimeMillis();
UUID uuid = UUID.randomUUID();
while (tryLockTimeout == 0 || (System.currentTimeMillis() - timestamp) < tryLockTimeout) {
String result = redisTemplate.execute(scriptLock, redisTemplate.getStringSerializer(),
redisTemplate.getStringSerializer(), Collections.singletonList(key), uuid.toString(),
String.valueOf(lockTimeout));
if (result != null && result.equals("OK")) {
logger.debug("获取锁成功:" + key);
return new RedisLock(key, uuid, lockTimeout, this);
} else {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
logger.error(e.toString(), e);
}
}
}
logger.debug("获取锁失败:" + key);
return null;
}
public RedisLock lockWithoutWait(String key) {
return lockWithoutWait(key, DEFAULT_LOCK_TIME_OUT);
}
public RedisLock lockWithoutWait(String key, long lockTimeout) {
key = key + ".lock";
UUID uuid = UUID.randomUUID();
String result = redisTemplate.execute(scriptLock, redisTemplate.getStringSerializer(),
redisTemplate.getStringSerializer(), Collections.singletonList(key), uuid.toString(),
String.valueOf(lockTimeout));
if (result != null && result.equals("OK")) {
logger.debug("获取锁成功:" + key);
return new RedisLock(key, uuid, lockTimeout, this);
}
logger.debug("获取锁失败:" + key);
return null;
}
public void unLock(RedisLock lock) {
if (lock == null) {
return;
}
redisTemplate.execute(scriptUnlock, redisTemplate.getStringSerializer(), redisTemplate.getStringSerializer(),
Collections.singletonList(lock.getKey()), lock.getUuid().toString());
logger.debug("释放锁成功:" + lock.getKey());
}
}