这里介绍了一种redis分布式锁的实现方式:
主要使用了redis命令为:SETNX,SET,GETSET,详细了解命令见:http://doc.redisfans.com/index.html
为了直观体现,下面是我的加锁实现代码:
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.xml.core.Complete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
/**
* Created by zhangfan on 2019/6/20 14:50
*/
@Complete
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
*
* @param key productId(商品id)
* @param value 当前时间+过期时间
* @return
*/
public boolean lock(String key, String value){
//使用redis的SETNX方法,加锁
if(redisTemplate.opsForValue().setIfAbsent(key,value)){
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
//锁过期了
if(!StringUtils.isEmpty(currentValue)
&& Long.parseLong(currentValue) < System.currentTimeMillis()){
String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
if(!oldValue.isEmpty() && oldValue.equals(currentValue)){
return true;
}
}
return false;
}
}
其中setIfAbsent()方法为SETNX方法,getAndSet()方法为GETSET方法。
虽然SETNX命令就可以做到加锁操作,当一个线程执行方法成功时则获取锁,其他线程等待,但是这有个致命的缺陷,就是当前执有锁的节点在执行java代码时,出现了异常,那么他就会抛出异常而不会释放锁,就会导致其他节点都不会拿到锁,造成死锁等待。
那么我下面用了GETSET命令,则是当上一个锁A因为某种原因超时了,那么就会有机会让下面的节点B获取到锁,主要原理是:首先我们获取当前key(A)的value,判断他锁超时了,那么就会用GETSET命令获取key的旧值value->A,判断他们相同则就可以让节点B获取锁。
Redis分布式锁实现及死锁解决
本文介绍了Redis分布式锁的实现方式,使用SETNX、SET、GETSET等命令。指出仅用SETNX加锁存在缺陷,若持有锁的节点异常,会导致死锁。采用GETSET命令可解决此问题,当上一锁超时时,后续节点有机会获取锁。
1847

被折叠的 条评论
为什么被折叠?



