基於Redis的單線程特性和Lua腳本,咱們能夠簡單的實現一把分佈式鎖。通常鎖在Redis上就是一個KV值,加鎖就是新建一個KV,釋放鎖就把這個KV刪除。利用Redis在設置KV時能夠設置NX和PX特性,咱們就能夠很方便的加鎖。廢話很少說,先上僞代碼:git
String kId = UuidUtil.uuid(); String result = jedis.set("lockName", kId, "NX", "PX", 30 * 1000);
在獲取鎖時,先在本地生成uuid,做爲鎖的鑰匙。而後用這個uuid做爲值去redis設置KV,同時指定NX模式,NX模式的意思就是若是不存在才新增這個KV,若是對應的K已經存在,則放棄新增。這裏返回的result=OK表示新增成功即加鎖成功,否者加鎖失敗。後面兩個參數PX表明,這個KV有一個過時時間,若是時間過時了,KV會被自動的刪除。這個就是解決了上面說到的,若是一個節點沒有即時返回鎖,那麼防止死鎖的出現,這裏有個鎖持有的超時時間。redis
釋放鎖很簡單,就是直接刪除這個KV。可是咱們要作到的是,誰獲取鎖誰纔有資格釋放,因此在釋放時,不能簡單的根據K來刪除,還須要匹配V的值,這樣才能保證誰拿的鎖,誰有資格釋放。如此一來,釋放鎖就須要兩個步驟。第一步:先獲取當前鎖對應的值,和本身手上的鑰匙是否匹配。第二步,在匹配符合時再操做刪除。因此這裏就要用Lua腳原本保證這兩個步驟的原子性。僞代碼以下:網絡
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; redis.eval(script, Collections.singletonList("lockName"), Collections.singletonList(kId));
簡單說明一下,這裏在本地編寫一段Lua腳本,大體意思你應該也能夠看出來了,先get取到鎖對應的值,判斷持有的kId是否相等,若是相等才進行del操做,進行鎖的刪除釋放。redis能夠原子的讓這個腳本執行。分佈式
剛纔說的所有代碼實現,在這個開源項目裏面有,裏面還有一些別的分佈式組件,若是對你有幫助,請給我個star哈。 https://gitee.com/xuan698400/distributed-toolui