原理
redis為單進(jìn)程單線程模式,采用隊(duì)列模式j(luò)將并發(fā)訪問變成串行訪問,多客戶端對(duì)redis的連接不存在競(jìng)爭(zhēng)關(guān)系,setnx命令來實(shí)現(xiàn)
命令
SETNX
將key
設(shè)置值為value
,如果key
不存在,這種情況下等同[SET](http://www.redis.cn/commands/set.html)命令。 當(dāng)key
存在時(shí),什么也不做。SETNX
是”SET if Not eXists”的簡(jiǎn)寫。
GETSET
自動(dòng)將key對(duì)應(yīng)到value并且返回原來key對(duì)應(yīng)的value。如果key存在但是對(duì)應(yīng)的value不是字符串,就返回錯(cuò)誤。
demo
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
*
* @param key
* @param value 當(dāng)前時(shí)間+超時(shí)時(shí)間
* @return
*/
public boolean lock(String key,String value){
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(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
return true;
}
}
return false;
}
public void unlock(String key,String value){
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) && value.equals(currentValue)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【redis分布式鎖】解鎖異常,{}",e);
}
}
}
1.解決死鎖的問題
當(dāng)程序中獲取鎖后,后面過程中出現(xiàn)異??赡軙?huì)導(dǎo)致所不能釋放,所以加入下面判斷來解決
String currentValue = redisTemplate.opsForValue().get(key);
//如果鎖過期
if(!StringUtils.isEmpty(currentValue)
&& Long.parseLong(currentValue) < System.currentTimeMillis()){
String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
return true;
}
}
2.確保只有一個(gè)線程獲得鎖
如下判斷來確保,所超時(shí)時(shí),當(dāng)有A,B兩個(gè)線程剛進(jìn)來,只有一個(gè)獲得鎖
if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
return true;
}
釋放鎖,就是刪除key
public void unlock(String key,String value){
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) && value.equals(currentValue)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【redis分布式鎖】解鎖異常,{}",e);
}
}