请老师帮忙看看,在RedisShardedPoolUtil中设置带有效期的锁的方法实现
来源:14-4 本章总结
慕慕8288485
2020-03-10
请老师帮忙看看,在RedisShardedPoolUtil.java 中这样实现有没有问题?谢谢~~
/**
* 带过期时间的分布式锁
*
* @param key
* @param seconds 有效期时间(秒)
* @return
*/
public static Long setnxEx(String key, int seconds) {
try {
try (ShardedJedis jedis = RedisShardedPool.getJedis()) {
// 尝试获取锁
Long setnxResult = jedis.setnx(key, String.valueOf(System.currentTimeMillis() + seconds * 1000));
if (setnxResult == null || setnxResult.intValue() != 1) {
// 未获取到锁,继续判断时间戳,看是否可以重置并获取到锁
String lockValueStr = jedis.get(key);
if (lockValueStr != null && System.currentTimeMillis() < Long.parseLong(lockValueStr)) {
// key存在且时间戳未过,获取锁失败
return 0L;
}
// key不存在(已经过期或被删除)或者时间戳已过,利用getset原子操作尝试获取
String getsetResult = jedis.getSet(key, String.valueOf(System.currentTimeMillis() + seconds * 1000));
if (getsetResult != null && !StringUtils.equals(lockValueStr, getsetResult)) {
// key已经被其他请求重置并获取锁,本次请求获取锁失败(负面后果:少量延长了该锁的时间戳)
return 0L;
}
// key不存在(已经过期或被删除)或者key的原值与前面获取的相同(表示没有其他请求重置key并获取到锁),获取锁成功
setnxResult = 1L;
}
// 获取锁成功,设置超时
Long expireResult = jedis.expire(key, seconds);
if (expireResult == null || expireResult.intValue() != 1) {
throw new Exception("set key: " + key + " expire error. return: " + expireResult);
}
return setnxResult;
}
} catch (Exception e) {
log.error("setnxEx key: {} error", key, e);
}
return null;
}
写回答
2回答
-
同学,可以写一个多线程并发的测试代码测试一下。
012020-03-11 -
慕慕8288485
提问者
2020-03-11
简单测试通过,基本上是实现课程中的逻辑。
redis2.6.x之后已经支持 SET 带 nx 和 ex的参数,作为一个原子操作,就不需要这么麻烦了吧。另外,Redisson通过eval一段lua代码来实现RedLock,还能实现可重入锁。看来,自己还得快点更新知识啊。
012020-03-14
相似问题