實現要點
互斥性,同一時刻,智慧型有乙個客戶端持有鎖。
防止死鎖發生,如果持有鎖的客戶端崩潰沒有主動釋放鎖,也要保證鎖可以正常釋放及其他客戶端可以正常加鎖。
加鎖和釋放鎖必須是同乙個客戶端。
容錯性,只有redis還有節點存活,就可以進行正常的加鎖解鎖操作。
正確的redis分布式鎖實現
錯誤加鎖方式
錯誤方式一
保證互斥和防止死鎖,首先想到的使用redis的setnx命令保證互斥,為了防止死鎖,鎖需要設定乙個超時時間。
public static void wronglock(jedis jedis, string key, string uniqueid, int expiretime) }1
2345
67在多執行緒併發環境下,任何非原子性的操作,都可能導致問題。這段**中,如果設定過期時間時,redis例項崩潰,就無法設定過期時間。如果客戶端沒有正確的釋放鎖,那麼該鎖(永遠不會過期),就永遠不會被釋放。
錯誤方式二
比較容易想到的就是設定值和超時時間為原子原子操作就可以解決問題。那使用setnx命令,將value設定為過期時間不就ok了嗎?
public static boolean wronglock(jedis jedis, string key, int expiretime)
string value = jedis.get(key);
//如果當前鎖存在,且鎖已過期
if (value != null && numberutils.tolong(value) < system.currenttimemillis())
}// 其他情況,加鎖失敗
return true;}1
2345
6789
1011
1213
1415
1617
1819
2021
乍看之下,沒有什麼問題。但仔細分析,有如下問題:
value設定為過期時間,就要求各個客戶端嚴格的時鐘同步,這就需要使用到同步時鐘。即使有同步時鐘,分布式的伺服器一般來說時間肯定是存在少許誤差的。
鎖過期時,使用 jedis.getset雖然可以保證只有乙個執行緒設定成功,但是不能保證加鎖和解鎖為同乙個客戶端,因為沒有標誌鎖是哪個客戶端設定的嘛。
錯誤解鎖方式
解鎖錯誤方式一
直接刪除key
public static void wrongreleaselock(jedis jedis, string key) 12
34簡單粗暴,直接解鎖,但是不是自己加鎖的,也會被刪除,這好像有點太隨意了吧!
解鎖錯誤方式二
判斷自己是不是鎖的持有者,如果是,則只有持有者才可以釋放鎖。
public static void wrongreleaselock(jedis jedis, string key, string uniqueid) }1
2345
6看起來很完美啊,但是如果你判斷的時候鎖是自己持有的,這時鎖超時自動釋放了。然後又被其他客戶端重新上鎖,然後當前執行緒執行到jedis.del(key),這樣這個執行緒不就刪除了其他執行緒上的鎖嘛,好像有點亂套了哦!
正確加鎖釋放鎖方式
基本上避免了以上幾種錯誤方式之外,就是正確的方式了。要滿足以下幾個條件:
命令必須保證互斥
設定的key必須要有過期時間,防止崩潰時鎖無法釋放
value使用唯一id標誌每個客戶端,保證只有鎖的持有者才可以釋放鎖
加鎖直接使用set命令同時設定唯一id和過期時間;其中解鎖稍微複雜些,加鎖之後可以返回唯一id,標誌此鎖是該客戶端鎖擁有;釋放鎖時要先判斷擁有者是否是自己,然後刪除,這個需要redis的lua指令碼保證兩個命令的原子性執行。
下面是具體的加鎖和釋放鎖的**:
@slf4j
public class redisdistributedlock
// 不斷嘗試加鎖
public string lock()
try catch (interruptedexception e)
}} catch (exception ex)
return null;
}
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不存在。如給定的...