关于redis分布式锁加锁释放锁的代码如下,为什么这么写就不解释了
//加锁
private boolean redisLock(String lockKey, String uniqueValue, int seconds) {
Jedis jedis = null;
try {
jedis = this.getJedis();
String result = jedis.set(lockKey, uniqueValue, "NX", "EX", seconds);
if ("OK".equals(result)){
return true;
}
}finally {
this.close(jedis);
}
return false;
}
//释放锁
public boolean redisUnlock(String lockKey, String uniqueValue) {
Jedis jedis = null;
try {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
jedis = this.getJedis();
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uniqueValue));
if (result.equals(1L)){
return true;
}
}finally {
this.close(jedis);
}
return false;
}
/**
*
* @param lockKey 锁名
* @param uniqueValue 唯一值
* @param seconds 锁过期时间
* @param retryCount 重试次数
* @param sleepTime 重试间隔时间
* @return
*/
public boolean lockRetry(String lockKey, String uniqueValue, int seconds, int retryCount, Long sleepTime) {
boolean flag = false;
try {
for (int i=0; i<retryCount; i++){
flag = this.redisLock(lockKey, uniqueValue, seconds);
if (flag) break;
Thread.sleep(sleepTime);
}
}catch (Exception e){
logger.error("lockRetry error,reason:", e);
}
return flag;
}
使用方法如下
boolean getLock = lockRetry(..);
if(!getLock){
//提示当前访问人数过多之类的
}
//拿到锁
execute your code
//最后释放锁
redisUnlock(..);
以下是个人理解
redis重试加锁,对于重试的间隔时间不好把控,时间太短,拿锁的线程还没有跑完,重试加锁肯定失败,时间太长,
可能已经被别的线程抢走了锁,导致到重试完指定次数都没有拿到锁!
不过,这种方式对于并发不算太高的还可以用,如果并发高的话就不太适用了。
如果是阻塞的方式会更好一些,获取不到锁线程阻塞,等到锁被释放去唤醒所有阻塞的线程,继续去争夺锁资源,
这样才是比较合理的!!那么就又回到单应用上去了,显然就没有意义了。
所以个人认为最好的方式还是增加重试次数(保证一定能拿到锁),重试间隔设置
短点(重试太长会导致线程完成任务的时间增加),这样才能保证每个线程都能正常完成任务!
举个例子:A拿到锁并执行了5秒(实际是不知道程序会执行多久,也无法估计),假设设置的重试间隔为8秒(大于5秒),
B拿不到锁等待8秒,A执行完毕5秒后释放了锁,B还在等待,等到
B继续去拿锁的时候锁已经被其他线程占用,导致B可能一直拿不到锁,所以重试间隔一定要小于程序执行时间!
大家有什么更好的想法,欢迎补充~