Redis分布式锁实现
redis一个命令setnx
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写
将 key 的值设为 value ,当且仅当 key 不存在.
返回值:
设置成功,返回 1 。
设置失败,返回 0 。
如下思路是设置一个过期锁。但是实际开发中这个过期时间很难判断,需要加守护线程进行重新设置过期时间。
public boolean tryLock(String key, String requestId, int expireTime) {
//使用jedis的api,保证原子性
//NX 不存在则操作 EX 设置有效期,单位是秒
String result = jedis.set(key, requestId, "NX", "EX", expireTime);
//返回OK则表示加锁成功
return "OK".equals(result);
}
有一种方法比较靠谱一点,就是给锁续期。在Redisson框架实现分布式锁的思路,就使用watchDog机制实现锁的续期。当加锁成功后,同时开启守护线程,默认有效期是30秒,每隔10秒就会给锁续期到30秒,只要持有锁的客户端没有宕机,就能保证一直持有锁,直到业务代码执行完毕由客户端自己解锁,如果宕机了自然就在有效期失效后自动解锁。
秒杀场景,幂等返回
使用自旋操作:
long timeout = 5000; // 5秒超时秒杀失败
try {
Long start = System.currentTimeMillis();
while(true) {
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
if ("OK".equals(result)) {
// 秒杀逻辑
return true;
}
long time = System.currentTimeMillis() - start;
if (time>=timeout) {
return false;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally{
unlock(lockKey,requestId);
}
return false;