1、利用redis的SETNX命令来实现分布式锁
SETNX key value 当前仅当key不存在时,为key设置value值,value是随机生成的UUID,返回1成功,如果key已经存在则返回0失败
以下加锁代码:
public String acquireLock(Jedis conn, String lockName) {
return acquireLock(conn, lockName, 10000);
}
public String acquireLock(Jedis conn, String lockName, long acquireTimeout){
String identifier = UUID.randomUUID().toString();
//给定acquireTimeout,如果锁获取失败,那么会不断的重试,知道成功获取锁或者超过给定的是时限为止
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end){
if (conn.setnx("lock:" + lockName, identifier) == 1){
return identifier;
}
try {
Thread.sleep(1);
}catch(InterruptedException ie){
Thread.currentThread().interrupt();
}
}
return null;
}
如果获取锁后,没有超时设置,将导致锁一直处于被获取的状态,以下为锁设置超时时间:
public String acquireLockWithTimeout(
Jedis conn, String lockName, long acquireTimeout, long lockTimeout)
{
String identifier = UUID.randomUUID().toString();
String lockKey = "lock:" + lockName;
//设置超时时间,获取锁成功后,超时释放锁,不会造成死锁
int lockExpire = (int)(lockTimeout / 1000);
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end) {
if (conn.setnx(lockKey, identifier) == 1){
conn.expire(lockKey, lockExpire);
return identifier;
}
//如果该锁没有设置超时时间,这加上超时时间
if (conn.ttl(lockKey) == -1) {
conn.expire(lockKey, lockExpire);
}
try {
Thread.sleep(1);
}catch(InterruptedException ie){
Thread.currentThread().interrupt();
}
}
// null indicates that the lock was not acquired
return null;
}
最后释放锁:
//不断的重试,直到锁释删除掉
public boolean releaseLock(Jedis conn, String lockName, String identifier) {
String lockKey = "lock:" + lockName;
while (true){
conn.watch(lockKey);
if (identifier.equals(conn.get(lockKey))){
Transaction trans = conn.multi();
trans.del(lockKey);
List<Object> results = trans.exec();
if (results == null){
continue;
}
return true;
}
conn.unwatch();
break;
}
return false;
}
以上是redis分布式锁的实现方式,代码摘自《redis实战》,不喜勿喷