先講下流程:
1.在redis中設定乙個鎖setnx(lockkey , currenttime+timeout)。
2.返回1代表之前沒有這個鎖,那麼就呼叫expire(lockkey)來重新設定超時時間,執行業務,接下來del(key),釋放鎖,最後結束。
3.返回0代表有這個鎖,那麼傳統流程中就直接結束。優化後,呼叫get(lockkey)來獲取這個鎖的超時時間的value。
3.1接下來判斷如果value不是空,並且已經超時的話,那麼呼叫getset(lockkey,currenttime+timeout)方法,重新設定value值,同時會返回乙個老的值,判斷如果這個值為空,或者舊值和新值相等,那麼代表這個鎖沒有變化,獲取鎖成功,呼叫第二步操作。
3.2如果條件不滿足,那麼結束任務。
模擬乙個需求,使用者提交訂單後,若干時間後如果還沒有支付,那麼關閉這個訂單。那麼我們需要用定時任務做輪詢,把超時的訂單全部刪除。
在分布式的情況下,多個程式,我只需要其中乙個執行這個定時任務,不需要所有程式都做輪詢,因此我們可以用到redis鎖來管理。接下來寫**:
@component
public class closeordertask else
system.out.println("關閉訂單定時任務關閉");
}private void closeorder(string lockname) throws interruptedexception
}
public static long setnx(string key , string value) catch (exception e)
redisshardedpool.returnresource(jedis);
return result;
}
每次請求都會去redis中找是否有鎖,如果有的話就不做刪除,如果沒有的話就插入一條,並且設定超時時間。執行結果:
這樣就實現了只有乙個可以執行的目的,但是這裡會有乙個死鎖的問題:假如程式執行到第9行,剛set進值,還沒有設定超時時間的時候,程式崩掉了,那麼這個鎖就一直待在redis中了,那也就死鎖了。
這種情況我們可以在定時任務中加乙個方法:
@predestroy
public void dellock()
@predestroy在程式結束時執行,但是僅限於shutdown這種平和的方式,如果kill程序,這個也是沒有用的,因此我們需要演進一下**:
@scheduled(cron = "0 */1 * * * ?")
public void closeorder2() throws interruptedexception else else
}else
}system.out.println("關閉訂單定時任務關閉");
}
public static string getset(string key , string value) catch (exception e)
redisshardedpool.returnresource(jedis);
return result;
}
其實通過**就很清楚地看出流程了,裡面用了多重防死鎖,這是因為在分布式環境下,程式可能不止2臺,那麼所有的機器同時執行大概率會有類似問題,所以我們通過多重驗證來判斷是否獲得鎖。 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不存在。如給定的...