基于redis的分布式锁实现
最近项目中用到了分布式锁,研究了下redis相关的方法,顺手实现了一下。
接口类:
import java.util.concurrent.TimeUnit;
public interface RedisLock {
/**
* 尝试获取key上的锁,获取不到立即返回false
* @param key
* @return
*/
public boolean tryLock(String key);
/**
* 尝试获取key上的锁(指定锁的超时时间),获取不到立即返回false
* @param key
* @param expireTimeMillis 锁的超时时间,毫秒
* @return
*/
public boolean tryLock(String key,long expireTimeMillis);
/**
* 循环尝试获取key上的锁(指定循环尝试超时时间)
* @param key
* @param timeout 循环尝试超时时间
* @param unit 时间单位
* @return
* @throws InterruptedException
*/
public boolean tryLock(String key,long timeout, TimeUnit unit) throws InterruptedException;
/**
* 循环尝试获取key上的锁(指定循环尝试超时时间,锁的超时时间)
* @param key
* @param time 循环尝试超时时间
* @param unit 时间单位
* @param expireTimeMillis 锁的超时时间,毫秒
* @return
* @throws InterruptedException
*/
public boolean tryLock(String key,long time, TimeUnit unit,long expireTimeMillis) throws InterruptedException;
/**
* 释放key上的锁
* @param key
*/
public void unLock(String key);
}
方法定义上借鉴了java.util.concurrent.locks中Lock类,具体方法作用见代码注释。
实现类:
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
public class RedisLockImpl implements RedisLock{
//这里引用自己项目中的redis客户端
private RedisClient redisClient;
/**
* 默认循环获取锁sleep时间1s
*/
private static final long SLEEP_MILLIS = 1000L;
/**
* 默认锁超时时间10s
*/
private static final long DEFAULT_EXPIRE_TIMEMILLIS = 10000L;
public boolean _tryLock(String key,long expireTimeMillis) {
if(StringUtils.isEmpty(key)){
throw new NullPointerException("lock key can not be empty");
}
boolean result = redisClient.setnx(key, String.valueOf(System.currentTimeMillis())) == 1L;
if(!result){
Long currentTime = System.currentTimeMillis();
String t1 = redisClient.get(key);
if(StringUtils.isEmpty(t1)){
return false;
}
//超时
if(currentTime - Long.parseLong(t1) >= expireTimeMillis){
String t2 = redisClient.getSet(key, String.valueOf(currentTime));
if(StringUtils.isNotEmpty(t2) && t2.equals(t1)){
result = true;
}
}
}
return result;
}
public boolean tryLock(String key){
return _tryLock(key,DEFAULT_EXPIRE_TIMEMILLIS);
}
@Override
public boolean tryLock(String key,long expireTimeMillis){
return _tryLock(key,expireTimeMillis);
}
@Override
public boolean tryLock(String key, long time, TimeUnit unit) throws InterruptedException{
return _tryLock(key, time, unit, DEFAULT_EXPIRE_TIMEMILLIS);
}
@Override
public boolean tryLock(String key,long time, TimeUnit unit,long expireTimeMillis) throws InterruptedException{
return _tryLock(key,time, unit,expireTimeMillis);
}
private boolean _tryLock(String key, long time, TimeUnit unit, long expireTimeMillis) throws InterruptedException{
if(StringUtils.isEmpty(key)){
throw new NullPointerException("lock key can not be empty");
}
return _tryLockNanos(key, unit.toNanos(time),expireTimeMillis);
}
private boolean _tryLockNanos(String key,long nanos,long expireTimeMillis) throws InterruptedException{
return _tryLock(key,expireTimeMillis) || _doTryLockNanos(key,nanos,expireTimeMillis);
}
private boolean _doTryLockNanos(String key,long nanosTimeout,long expireTimeMillis) throws InterruptedException{
if(nanosTimeout <= 0L){
return false;
}
final long deadline = System.nanoTime() + nanosTimeout;
for(;;){
if(_tryLock(key,expireTimeMillis)){
return true;
}
nanosTimeout = deadline - System.nanoTime();
if(nanosTimeout <= 0L){
return false;
}
Thread.sleep(SLEEP_MILLIS);
if (Thread.interrupted()){
throw new InterruptedException();
}
}
}
@Override
public void unLock(String key) {
redisClient.del(key);
}
}
具体使用示例:
if(redisLock.tryLock("lockKey")){
try{
//业务逻辑
}finally{
redisLock.unLock("lockKey");
}
}

浙公网安备 33010602011771号