最近研究了下redis分布式鎖,分享下演變過程,怎麼一步步實現抗高併發的分布式鎖
@override
public string seckill()
else
return goodscount >=0?
"恭喜你,搶到商品"
:"抱歉,您沒搶到"
;}
這段**,單執行緒情況下,無任何問題,一旦涉及到多執行緒,就涉及到先後順序,得先查詢redis獲取庫存,然後減庫存,將剩餘庫存存入redis,這段操作需要原子執行才行
毫無疑問synchronized 和 reentrantlock在集群環境下是不可行的,這裡不做贅述
**變成了這樣
string goodsid =
"666666"
; string lockkey =
"lockkey"
; boolean lock = redistemplate.
opsforvalue()
.setifabsent
(lockkey,
"***");
if(lock)
else
redistemplate.
delete
(lockkey)
;return goodscount >=0?
"恭喜你,搶到商品"
:"抱歉,您沒搶到";}
else
增加了獲取鎖和刪除鎖的過程,如果獲取到了鎖,執行秒殺操作,獲取不到鎖,繼續執行獲取鎖的操作;
但是這樣寫出現了個問題,如果來不及執行刪除鎖的**,拋異常或者服務宕機了,那麼其他執行緒永遠獲取不到鎖,變成了死鎖了,於是下面開始改進:
將setnx加上過期時間
boolean lock = redistemplate.opsforvalue().setifabsent(lockkey, 「***」,30, timeunit.seconds);
這樣就算服務宕機了,也能釋放鎖,不至於造成死鎖。
但是又引發出來了新的問題,有2個執行緒,執行緒一需要10s執行完成,執行緒二需要35秒執行完成,執行緒二30秒**沒執行完,這時候執行緒一執行完成刪除了鎖,這時候會有新的執行緒獲取到鎖,執行緒二執行完成後,又刪除了別人的鎖,於是開始下面的演變
@override
public string seckill() else
return goodscount >= 0 ? "恭喜你,搶到商品" : "抱歉,您沒搶到";
}finally
}}else
這樣還有個問題,執行時間還是個問題,**執行時間不一致,無法保證所有請求在30秒或者指定時間內執行完成,還是存在刪除別人鎖的情況,目的就是在**沒有執行完成時不要刪除鎖,**執行完成才刪除鎖,改進方法就是鎖續期,專門開啟乙個執行緒,每隔10秒,(1/3的時間)檢查鎖是否還存在,如果存在,就將時間續期為30秒
timeout task = commandexecutor.getconnectionmanager().newtimeout(new timertask()
if (future.getnow())
}});
}}, internallockleasetime / 3, timeunit.milliseconds);
if (expirationrenewalmap.putifabsent(getentryname(), new expirationentry(threadid, task)) != null)
先查詢是否是自己的鎖,然後再刪除鎖也要是原子執行
至此,redis分布式鎖算比較完整的了,redis官方給我們最好了這一套,可以直接使用redisson redis分布式鎖
redis分布式鎖 直接上 我寫了四個redis分布式鎖的方法,大家可以提個意見 第一種方法 redis分布式鎖 param timeout public void lock long timeout thread.sleep 100 catch exception e override publi...
Redis分布式鎖
分布式鎖一般有三種實現方式 1.資料庫樂觀鎖 2.基於redis的分布式鎖 3.基於zookeeper的分布式鎖.首先,為了確保分布式鎖可用,我們至少要確保鎖的實現同時滿足以下四個條件 互斥性。在任意時刻,只有乙個客戶端能持有鎖。不會發生死鎖。即使有乙個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保...
redis分布式鎖
使用redis的setnx命令實現分布式鎖 redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多個客戶端對redis的連線並不存在競爭關係。redis的setnx命令可以方便的實現分布式鎖。setnx key value 將key的值設為value,當且僅當key不存在。如給定的...