一些引數說明
dynmaicconfigurerbean:專案中配置,方便獲取動態屬性。
超時時間預設1s,重試次數預設5次,睡眠時間預設200ms
流程圖
流程圖及關鍵函式說明
long expires = system.currenttimemillis() + timeout + 1;
設定分布式鎖的超時時間
redisclient.setnx(lockkey, expiresstr)
嘗試獲取鎖,鍵為鎖的名字,值為超時時間
如果獲取成功就返回。
沒有獲取會走下面邏輯:分析
/**
1. 對於以下部分場景考慮的【重要注釋】:
2. ① 某一時刻所有執行緒都檢測到之前已經成功獲取鎖的執行緒已經持有鎖。
3. 此時,如果檢測到已持有鎖的執行緒已經鎖超時,那麼他們可以通過cas機制競爭鎖,可以保證只有乙個執行緒獲取鎖。
4. ② 某一時刻,之前有乙個執行緒已經獲取鎖了,剩餘的執行緒,會發現鎖的生命週期結束時間大於當前時間,因此不會獲取鎖。
5. ③判斷過期時間的好處:如果在發布時的時候,或者因為某些原因機器崩潰,假設碰巧沒有解鎖,那麼就會產生死鎖,判斷過期時間也有自動檢測死鎖的功能。
6. ④ 對於多執行緒getset會不會讓鎖的生存週期結束時間更新?首先,即使更新,分布式鎖的判斷依據是是否獲取鎖,並不關心超時的情況,並且對於已經獲取鎖
7. 的執行緒會解鎖。即使已經獲取鎖的執行緒超時了,但是對應key值的value值已經被重新賦值生命週期,但是因為既然是鎖競爭,走到這裡他們的生存週期的截止時間
8. 都是相近的,也沒有什麼問題。
*/
string currentvaluestr = redisclient.get(lockkey);
long.parselong(currentvaluestr) < system.currenttimemillis()
沒有獲取到鎖則獲取該鎖的超時時間,判斷超時時間有沒有超過當前時間
string oldvaluestr = redisclient.getset(lockkey, expiresstr);
如果已經小於當前時間,說明獲得鎖的執行緒並沒有及時釋放鎖,則去cas搶鎖,搶鎖成功,則返回
沒有搶到,則重試次數加1,重試次數大於閾值,則退出,否則睡眠一段時間再重試。
**實現
@component
public
class
distributedlock
/** * 以下**是對於以下部分場景考慮的【重要注釋】:
* ① 某一時刻所有執行緒都檢測到之前已經成功獲取鎖的執行緒已經持有鎖,那麼都會走到這兒來。
* 此時,如果檢測到已持有鎖的執行緒已經鎖超時,那麼他們可以通過cas機制競爭鎖,可以保證只有乙個執行緒獲取鎖。
* ② 某一時刻,如果所有執行緒走到這裡,之前有乙個執行緒已經獲取鎖了,剩餘的執行緒,會發現鎖的生命週期結束時間大於當前時間,因此不會獲取鎖。
* ③ 這個地方,能不能對於沒有獲取鎖的直接返回?如果在發布時的時候,或者因為某些原因機器崩潰,假設碰巧沒有解鎖,那麼就會產生死鎖,這個
* 地方也有自動檢測死鎖的功能。
* ④ 對於多執行緒getset會不會讓鎖的生存週期結束時間更新?首先,即使更新,分布式鎖的判斷依據是是否獲取鎖,並不關心超時的情況,並且對於已經獲取鎖
* 的執行緒會解鎖。即使已經獲取鎖的執行緒超時了,但是對應key值的value值已經被重新賦值生命週期,但是因為既然是鎖競爭,走到這裡他們的生存週期的截止時間
* 都是相近的,也沒有什麼問題。
*/string currentvaluestr = redisclient.
get(lockkey);if
(!strings.
isnullorempty
(currentvaluestr)
&& long.
parselong
(currentvaluestr)
< system.
currenttimemillis()
)}count++
; logger.
info
(loghead +
"分布式鎖搶鎖次數="
+ count +
",lockkey="
+ lockkey);if
(count > retrycount)
thread.
sleep
(sleeptime)
;// 睡一會,然後再次嘗試搶鎖
} logger.
info
(loghead +
"lock-目標已經被加鎖[1],lockkey="
+ lockkey +
",timeout[ms]="
+ timeout)
;return
newlockbean(1
, null);}
else
}catch
(exception e)
}/**
* 分布式鎖-解鎖
* @param loghead 日誌頭
* @param lockkey key
*/public
void
unlock
(string loghead, string lockkey, lockbean lockbean)
else
}catch
(exception e)
}}
分布式鎖 使用Redis實現分布式鎖
關於分布式鎖的實現,我的前一篇文章講解了如何使用zookeeper實現分布式鎖。關於分布式鎖的背景此處不再做贅述,我們直接討論下如何使用redis實現分布式鎖。關於redis,筆主不打算做長篇大論的介紹,只介紹下redis優秀的特性。支援豐富的資料型別,如string list map set zs...
redis實現分布式鎖
隨便 系統越來越大,各功能模組除了垂直切割以外,同時也得做集群處理,那麼問題來了,在多執行緒情況下對於資源的競爭就需要乙個統一的訪問限制。以選課系統為例子,集群中各節點對課程可選數量同時操作,這裡就需要同步了,否則會導致最後選到的數量比可選的數量大,這裡我們的分布式鎖就派上用場了。利用redis來實...
redis實現分布式鎖
分布式鎖可以基於很多種方式實現,比如zookeeper redis.不管哪種方式,他的 基本原理是不變的 用乙個狀態值表示鎖,對鎖的占用和釋放通過狀態值來標識。1 使用redis的setnx命令實現分布式鎖 1 實現的原理 redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多客戶...