?SETNX ,命令解釋http://redis.cn/commands/setnx.html,GETSET,命令解釋http://redis.cn/commands/getset.html。
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
*@Description
*@Date 14:10 2018/6/17
*@Param value:當(dāng)前時(shí)間+超時(shí)時(shí)間
*@return
**/
public boolean lock(String key,String value){
if (redisTemplate.opsForValue().setIfAbsent(key,value)){
return true;
}
//下面代碼解決了 死鎖問題 和 保證只有一個(gè)線程拿鎖。
/**1.死鎖 。當(dāng)相關(guān)代碼之前上鎖后,如果執(zhí)行代碼的過程中拋錯(cuò)了,
那么就會(huì)出現(xiàn)沒有解鎖的問題,后續(xù)線程無法獲得鎖,也就出現(xiàn)了死鎖的問題。
而以下代碼后有返回true的可能,也就解決了死鎖問題。
*/
/**2.保證只有一個(gè)線程拿鎖。比如兩個(gè)線程同時(shí)進(jìn)入下面代碼,并且其value都為B,currentValue = A。
一條代碼只可能一個(gè)線程執(zhí)行。
當(dāng)?shù)谝粋€(gè)線程執(zhí)行時(shí),oldvalue = A,如果符合if條件成功拿鎖。
當(dāng)?shù)诙€(gè)執(zhí)行時(shí)oldValue就已經(jīng)是B了,所以保證了只有一個(gè)線程拿鎖。
*/
String currentValue = redisTemplate.opsForValue().get(key);
//如果鎖過期
if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){
//獲取上一個(gè)鎖的時(shí)間
String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
return true;
}
}
return false;
}
/**
*@Author banrityan
*@Description 解鎖
*@Date 14:25 2018/6/17
*@Param
*@return
**/
public void unlock(String key,String value){
try{
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【redis分布式鎖】解鎖異常,{}",e);
}
}
}
?解釋在代碼注釋中。
?然后值需要在要執(zhí)行的代碼前加鎖
//加鎖
long time = System.currentTimeMillis() + TIMEOUT;
if (!redisLock.lock(productId,String.valueOf(time))){
throw new SellException(101,"哎喲喂,人太多,請稍后再試~~");
}
?然后執(zhí)行完后記得解鎖
//解鎖
redisLock.unlock(productId,String.valueOf(time));
內(nèi)容如上。\( ̄︶ ̄)/
參考資料:無所不知的度娘+各位大佬的博客