一個操做須要進行讀變量,寫變量兩個步驟,多個相同的操做同時進行就會出現併發問題。由於讀取和寫入兩個變量不是原子操做。html
分佈式鎖本質上要實現的目標就是在 Redis 裏面佔一個「茅坑」,當別的進程也要來佔時,發現已經有人蹲在那裏了,就只好放棄或者稍後再試。算法
佔坑通常是使用 setnx(set if not exists) 指令,只容許被一個客戶端佔坑。先來先佔, 用完了,再調用 del 指令釋放茅坑。併發
加鎖分佈式
setnx lock:a true
釋放鎖線程
del lock:a
爲了不加鎖後,中間操做出現異常,最後沒有釋放鎖的問題,須要給鎖設置一個超時時間。設計
setnx lock:a true expire lock:a 5
出現另外一個問題,上面的操做也有可能失敗,例如設置過時時間失敗。code
爲了解決上述的問題,Redis2.8增長了set指令的擴展參數,htm
set lock:a true ex 5 nx
若是執行代碼的時間太長,超出了鎖的超時限制,就會由其餘線程得到鎖。會致使代碼不能嚴格被執行。爲了不這個狀況,進行加鎖的執行代碼儘可能不要選擇執行時間過長的。對象
可重入性指的是線程在持有鎖的狀況下,再次請求加鎖。blog
問題,爲什麼要設計可重入這一個特性?
搞清楚幾個概念:可重入鎖、公平鎖、非公平鎖。
可重入鎖:
線程1執行 synchronized A()方法,A()方法調用synchronized B()方法,當線程1獲取到A方法對應的對象鎖以後,再去調用B方法,就不須要從新申請鎖。
公平鎖:
多個線程等待鎖,當鎖釋放後,等待該鎖時間最久的(或者說最早申請鎖的),應該得到鎖。
非公平鎖:
多個線程等待鎖,不按照等待鎖的時間或申請鎖的前後順序,來得到鎖。
[1]: 《Redis 深度歷險:核心原理與應用實踐》
[2]: 經過一個故事理解可重入鎖的機制
[3]: JAVA鎖機制-可重入鎖,可中斷鎖,公平鎖,讀寫鎖,自旋鎖
[4]: 80% 人不知道的 Redis 分佈式鎖的正確實現方式(Java 版)