redis実装の分散ロックについて簡単に説明します
5536 ワード
詳細
/**
* Created by BingZhong on 2017/7/29.
*
* Redis
*/
public final class RedisLockHelper {
private static Logger logger = LoggerFactory.getLogger(RedisLockHelper.class);
/**
* redis , redis
*/
private RedisHelper redisHelper;
public static final long DEFAULT_TIMEOUT = 30 * 1000;
public static final long DEFAULT_SLEEP_TIME = 100;
private RedisLockHelper(RedisHelper redisHelper) {
this.redisHelper = redisHelper;
}
public static RedisLockHelper getInstance(RedisHelper redisHelper) {
return new RedisLockHelper(redisHelper);
}
/**
*
*
* @param mutex
* @param timeout
* @param sleepTime
* @param timeUnit
*/
public RedisLock newLock(String mutex, long timeout, long sleepTime, TimeUnit timeUnit) {
logger.info(" , {}", mutex);
return new RedisLock(mutex, timeout, sleepTime, timeUnit);
}
public RedisLock newLock(String mutex, long timeout, TimeUnit timeUnit) {
return newLock(mutex, timeout, DEFAULT_SLEEP_TIME, timeUnit);
}
public RedisLock newLock(String mutex) {
return newLock(mutex, DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
public class RedisLock {
/**
* redis ,
*/
private final String mutex;
/**
*
*/
private volatile long lockExpiresTime = 0;
/**
*
*/
private final long timeout;
/**
*
*/
private final long sleepTime;
/**
*
*/
private volatile Thread lockHolder = null;
private final ReentrantLock threadLock = new ReentrantLock();
public RedisLock(String mutex, long timeout, long sleepTime, TimeUnit timeUnit) {
this.mutex = mutex;
this.timeout = timeUnit.toMillis(timeout);
this.sleepTime = timeUnit.toMillis(sleepTime);
}
/**
* , ,
*/
public boolean lock(long acquireTimeout, TimeUnit timeUnit) throws InterruptedException {
acquireTimeout = timeUnit.toMillis(acquireTimeout);
long acquireTime = acquireTimeout + System.currentTimeMillis();
threadLock.tryLock(acquireTimeout, timeUnit);
try {
while (true) {
boolean hasLock = tryLock();
if (hasLock) {
//
return true;
} else if (acquireTime < System.currentTimeMillis()) {
break;
}
Thread.sleep(sleepTime);
}
} finally {
if (threadLock.isHeldByCurrentThread()) {
threadLock.unlock();
}
}
return false;
}
/**
* ,
*
*/
public boolean tryLock() {
if (lockHolder == Thread.currentThread()) {
throw new IllegalMonitorStateException(" ");
}
long currentTime = System.currentTimeMillis();
String expires = String.valueOf(timeout + currentTime);
//
if (redisHelper.setNx(mutex, expires) > 0) {
setLockStatus(expires);
return true;
} else {
String currentLockTime = redisHelper.get(mutex);
//
if (Objects.nonNull(currentLockTime) && Long.parseLong(currentLockTime) < currentTime) {
//
String oldLockTime = redisHelper.getSet(mutex, expires);
// , ( )
if (Objects.nonNull(oldLockTime) && Objects.equals(oldLockTime, currentLockTime)) {
setLockStatus(expires);
return true;
}
}
return false;
}
}
/**
*
*/
public boolean isLock() {
String currentLockTime = redisHelper.get(mutex);
//
return Objects.nonNull(currentLockTime) && Long.parseLong(currentLockTime) > System.currentTimeMillis();
}
public String getMutex() {
return mutex;
}
/**
*
*/
public boolean unlock() {
//
if (lockHolder == Thread.currentThread()) {
// ,
if (lockExpiresTime > System.currentTimeMillis()) {
redisHelper.del(mutex);
logger.info(" [{}]", mutex);
}
lockHolder = null;
logger.info(" [{}] ", mutex);
return true;
} else {
throw new IllegalMonitorStateException(" ");
}
}
private void setLockStatus(String expires) {
lockExpiresTime = Long.parseLong(expires);
lockHolder = Thread.currentThread();
logger.info(" [{}] ", mutex);
}
}
}