分布式鎖
通過2個原子性的命令setnx
getset
還有
expire
設(shè)有效期
del
刪除
第一版分布式鎖
版本1
public void 分布式鎖版本1(){
Long setnxResult = RedisShardedPoolUtil.setnx(key, 現(xiàn)在時間);
//mark 如果允許到這 tomcat重啟了 鎖還沒有加期限 這個鎖就永遠(yuǎn)不會被釋放了 沒人可以再得到鎖了
//如果是正常關(guān)閉 delLock能解決
if(setnxResult != null && setnxResult.intValue() == 1){
//如果返回值是1,代表設(shè)置成功,獲取鎖 closeOrder還會設(shè)定過期時間 完成后刪除鎖
RedisShardedPoolUtil.expire(key,50);//有效期 50秒,防止死鎖
//業(yè)務(wù)執(zhí)行
RedisShardedPoolUtil.del(key); //釋放鎖
}
}
但是如果得到鎖,還沒設(shè)有效期 tomcat就重啟了,這個鎖就永遠(yuǎn)沒人能得到了
Redis 2.8 版本中作者加入了 set 指令的擴(kuò)展參數(shù),使得 setnx 和 expire 指令可以一起執(zhí)行
set lock:codehole true ex 5 nx
為了防止這種情況
//tomcat 正常關(guān)閉前會調(diào)用
@PreDestroy
public void delLock(){
//釋放鎖
RedisShardedPoolUtil.del(key);
}
雖然可以@PreDestroy讓tomcat關(guān)閉前調(diào)用,但是tomcat不一定是正常關(guān)閉,如果要好多鎖需要釋放,tomcat就會很慢
第二版分布式鎖
第二版
第二版就是利用了setnx進(jìn)去的過期時間,如果這個值過期了 也算拿到鎖
public void 第二版() {
Long setnxResult = RedisShardedPoolUtil.setnx(key, 現(xiàn)在時間);
//順利拿到鎖
if (setnxResult != null && setnxResult.intValue() == 1) {
//業(yè)務(wù)
RedisShardedPoolUtil.del(key); //釋放鎖
return;
}
//未獲取到鎖,繼續(xù)判斷,判斷時間戳,看是否可以重置并獲取到鎖
String oldValue = RedisShardedPoolUtil.get(key);
//再看這個鎖沒有了,或者那個鎖超時了
if (oldValue != null && System.currentTimeMillis() > Long.parseLong(oldValue)) {
//再次用當(dāng)前時間戳getset。
String getSetResult = RedisShardedPoolUtil.getSet(key, 現(xiàn)在時間);
//當(dāng)key沒有舊值時,即key不存在時,返回nil ->獲取鎖
// 舊值就是我們剛才看到的過期的那個 ->獲取鎖
if (getSetResult == null || StringUtils.equals(oldValue, getSetResult)) {
//業(yè)務(wù)
RedisShardedPoolUtil.del(key); //釋放鎖
return;
}
}
//沒有獲取到分布式鎖:
}
第三版分布式鎖 用Redssion
@Autowired
private RedissonManager redissonManager;
// @Scheduled(cron="0 */1 * * * ?")
public void 第三版(){
RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
boolean getLock = false;
try {
//等待0秒(只能填0),最多持有鎖50秒
getLock = lock.tryLock(0, 50, TimeUnit.SECONDS);
if(getLock){
log.info("Redisson獲取到分布式鎖:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
// 業(yè)務(wù)代碼
}else{
log.info("Redisson沒有獲取到分布式鎖:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
}
} catch (InterruptedException e) {
log.error("Redisson分布式鎖獲取異常",e);
} finally {
//如果拿到鎖了就要釋放
if(getLock){
lock.unlock();
log.info("Redisson分布式鎖釋放鎖");
}
}
}