在程序中使用setnx实现分布式锁或许是可行的
来源:4-4 如何实现分布式锁

mapper
2019-08-14
老师好,
按照先setnx然后再expire的确存在没有执行到expire引发的独占锁的问题。不过在程序中我们可以只需要setnx一条原子性的命令即可实现,思路如下:
setnx的key为请求标识(requestId),value为该key的过期时间戳
。我们可以根据该时间戳来解决expireTime的问题,总的来说就是根据时间来判断锁是否过期以及是否进入死锁状态。代码如下
/**
* 加锁
* @param key seckillId
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key, String value) {
// 可以设置返回true (setnx)
Boolean isLock = redisTemplate.opsForValue().setIfAbsent(key, value);
if (isLock) {
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
// 如果锁已经过期
if (!StringUtils.isEmpty(currentValue)
&& Long.valueOf(currentValue) < System.currentTimeMillis()) {
// 获取上一个锁的时间,并设置新锁的时间
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue)
&& oldValue.equals(currentValue)) {
log.info("旧锁已过期,本次加锁成功");
return true;
}
}
return false;
}
然后我们在解锁的时候将该key给清除,即使解锁的时候出现了错误,因为时间戳的缘故,也不会进入死锁的状态。
不知道这种方案是否可行,请老师指点一下
extra
在评论区看到了一些恶意评论,其实有些评论都是其他平台请的水军,故意刷的(很多都是同一个人),感觉有点搞人心态… 其实不必在意这些;至少对我个人来说,收获还是很大的。
写回答
1回答
-
同学好,同学的思路很不错,多思考能成长得很快,这个方法如果针对单线程还可以(但是失去了分布式锁的意义),如果是多个线程的话,可能还是有问题的,因为会有同一时刻两个线程都返回true的情况,比如线程1执行到
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
而线程2执行到
String currentValue = redisTemplate.opsForValue().get(key);
就会拿到线程1的currentValue,
此时两个线程的
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue))
都成立:)
就会有隐患
特别感谢同学对翔仔的支持,让翔仔觉得很欣慰,我会用我的热情和坚持来服务好尽可能多的同学:)
072019-08-20
相似问题