分布式鎖正確打開方式 程序怎樣實現死鎖?該如何分析死鎖?
程序怎樣實現死鎖?該如何分析死鎖?所謂死鎖:是指兩個或兩個以上的進程在執(zhí)行過程中因為爭奪資源而相互等待的現象。如果沒有外力,他們就無法前進。此時,系統(tǒng)被稱為處于死鎖狀態(tài)或系統(tǒng)有死鎖。這些總是互相等待的
程序怎樣實現死鎖?該如何分析死鎖?
所謂死鎖:是指兩個或兩個以上的進程在執(zhí)行過程中因為爭奪資源而相互等待的現象。如果沒有外力,他們就無法前進。此時,系統(tǒng)被稱為處于死鎖狀態(tài)或系統(tǒng)有死鎖。這些總是互相等待的進程稱為死鎖進程。由于資源的占用是互斥的,當一個進程申請資源時,如果沒有外力的協(xié)助,相關進程永遠無法分配到必要的資源,這就產生了一種特殊的死鎖現象。
雖然在運行過程中可能會出現死鎖,但必須滿足一定的條件,死鎖必須滿足以下四個必要條件。
1)互斥情況:指一個進程獨占使用分配的資源,即一段時間內一個資源只被一個進程占用。如果此時有其他進程請求資源,請求者只能等待,直到占用資源的進程用完釋放。
2)請求和保持條件:指已經保持了至少一個資源的進程,但是提出了新的資源請求,并且這個資源已經被其他進程占用。此時,請求進程被阻塞,但是它仍然持有它已經獲得的其他資源。
3)非剝奪條件:指進程獲得的資源,在用完之前不能被剝奪,用完之后才能自行釋放。
4)循環(huán)等待條件:發(fā)生死鎖時,必須有一個進程——一個環(huán)形的資源鏈,即進程集{P0,P1,P2,..,Pn}正在等待P1占用的一個資源;P1正在等待被P2占領的資源,...,并且Pn正在等待已經被P0占用的資源。
系統(tǒng)發(fā)生死鎖后,應及時檢測并采取適當措施解除死鎖。目前,處理死鎖的方法可以歸納為以下四種
1)防止死鎖
這是一種比較簡單直觀的提前預防方法。方法是設置一些限制來破壞死鎖的四個必要條件中的一個或多個,從而防止死鎖。死鎖預防是一種易于實現的方法,已被廣泛使用。然而,所施加的限制往往過于嚴格,這可能導致系統(tǒng)資源利用率和系統(tǒng)吞吐量的降低。
2)避免死鎖
這種方法也是一種預防策略,但不需要事先采取各種限制性措施來破壞死鎖的四個必要條件,而是在動態(tài)分配資源的過程中使用一些方法來防止系統(tǒng)進入不安全狀態(tài),從而避免死鎖。
3)檢測死鎖
這種方法不需要事先采取任何限制措施,也不需要檢查系統(tǒng)是否進入了不安全區(qū)。這種方法允許系統(tǒng)在操作過程中出現死鎖。但是,通過系統(tǒng)設置的檢測機制,可以及時檢測到死鎖的發(fā)生,并準確地確定與死鎖相關的進程和資源,然后采取適當的措施從系統(tǒng)中清除已經發(fā)生的死鎖。
4)消除僵局
這與檢測死鎖是兼容的。測度集。當在系統(tǒng)中檢測到死鎖時,進程必須從死鎖狀態(tài)中釋放出來。常見的實現方法是取消或掛起一些進程,以便回收一些資源,然后將這些資源分配給已經處于阻塞狀態(tài)的進程,使其做好繼續(xù)運行的準備。死鎖檢測和消除措施可以使系統(tǒng)獲得更好的資源利用率和吞吐量,但也是最難實現的。
悲觀鎖:假設將發(fā)生并發(fā),所有可能違反數據完整性的操作都將被屏蔽。
樂觀鎖定:假設不會發(fā)生并發(fā),我們只會在提交操作時檢查是否違反了數據完整性。樂觀鎖定可以 解決不了骯臟閱讀的問題。
悲觀鎖,顧名思義就是悲觀。每次獲取數據的時候都認為別人會修改,所以每次獲取數據的時候都會加鎖,這樣別人就會屏蔽它,直到它得到鎖。傳統(tǒng)的關系數據庫中使用了許多這樣的鎖機制,如行鎖、表鎖、讀鎖、寫鎖等。,操作前全部鎖定。
樂觀鎖,顧名思義,就是樂觀。每次去取數據,他都認為別人不會修改,所以他贏了 不要鎖。但是在更新的時候,他會判斷這段時間別人有沒有更新過數據,他可以使用版本號等機制。樂觀鎖定適用于多讀應用程序類型,可以提高吞吐量。例如,如果數據庫提供類似write_condition的機制,它實際上提供了樂觀鎖定。
我的頭條號有更多關于發(fā)行、網站、開發(fā)語言等視頻。你可以看看。
如何保證同一資源被多個線程并發(fā)訪問時的完整性?
對于這個問題,我們首先想到的是使用synchronized關鍵字,這是一個解決方案,比如:
公共同步void setStatus(布爾b) {}
但是synchronized不適合高并發(fā)數據,會導致程序特別慢,不適合集群,負載均衡后數據會有問題。
我們使用另一種解決方案,redis分布式鎖。redis是單線程服務,高效的鍵/值結構,支持高可用的分布式集群,可以讓多臺機器上的多個進程互斥相同的數據。
讓 讓我們談談redis從創(chuàng)建到使用的過程:
1.使用maven下載redis所依賴的包,在pom.xml中進行配置:
ltdependencygt ltartifactidgt spring-boot-starter-data-redi SLT/artifactIdgt
2.熟悉r:在設置新值之前獲取以前的值。
3、新增redis類寫鎖,解鎖方法:
redis的自動注入
@自動連線
私有字符串模板
/***
*鎖定
* @param密鑰id
* @param value當前時間超時
* @return*/
命令對應的公共布爾鎖(String Key,String Value) {//setnx。
//可以設置值返回true,但是可以 不要將該值設置為返回false。
if(redisTemplate.opsForValue()。setIfAbsent(key,value)) { return true }
//確保只有一個線程獲得鎖。
字符串current value redis template . ops for value()。獲取(鍵)
//如果鎖過期,則存儲的鎖小于當前時間。
如果(!(當前值)ampamp(當前值)lt ()) {
//獲取最后一次鎖定的時間
string old value redis template . opsforvalue()。getAndSet(鍵,值)
如果(!(old value)amp old value . equals(current value)){ return true } } return false }
/**
*解鎖
*/public void unlock(字符串鍵,字符串值){
嘗試{
字符串current value redis template . ops for value()。get(key) if(!(當前值)ampamp當前值. equals(值)){
值()的Redisttemplate.ops。getOperations()。delete(key)} Catch(Exception e){([Redis分布式鎖]解鎖異常,{}