場景:
假如線程A獲取分布式鎖進入方法A,由於某種原因Hang住了 到了指定時間釋放鎖,這個時候線程B進入得到鎖,這個時候線程B很順利完成業務邏輯操作,然后釋放掉鎖,就在這個時候線程A開始繼續往下執行代碼,按照這個邏輯他最終會執行finally代碼塊 執行到釋放鎖的邏輯
那么這個時候如果鎖的值一樣,很有可能會釋放掉已經獲取鎖的線程持有的那把鎖。
那么該如何設計呢?
答案很簡單,可以把鎖的值設為UUID,保證唯一,這樣每個線程的鎖的值都是不一樣的!
我們釋放REDIS的鎖 是通過執行LUA腳本實現的
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
調用的時候,鎖的值是UUID的值。那為什么要設計為UUID的值,而不是隨便來一個值呢?
String lockVal = UUID.randomUUID().toString();
public boolean unlock(String lockName, String lockVal) { log.info("釋放redis鎖 {}", lockVal); Object eval = redisTemplate.execute(unlockLuaScript, Lists.newArrayList(lockName), lockVal); if (eval != null) { ArrayList<Long> evalArr = (ArrayList<Long>) eval; boolean b = evalArr.get(0) == 1; if (b) { log.info("釋放redis鎖成功 {}", lockVal); return true; } } log.error("釋放redis鎖超時 {}", lockVal); return false; }
上面這段代碼解釋了為什么redis鎖的值要設計成為UUID的uuid形式 因為假如redis業務邏輯時間執行的比較長,可能導致超時釋放鎖,那么另一線程獲取鎖,其執行完相關業務代碼后,釋放了鎖。然后上一個線程執行完邏輯后,繼續執行 (這個時候它是無鎖的狀態)但還是會去釋放鎖因為finally代碼會最終執行!