開發中要注意如何避免死鎖、活鎖問題

2020-12-25 老徐聊java

談到死鎖,相信大家都不陌生,耳熟能詳了吧,這個死鎖無論是在學習中、還是面試中都是必說的一個問題。小編先佔用大家時間說下什麼是死鎖?死鎖是指兩個或兩個以上的線程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。舉個例子:如2個廚師做飯,徐師傅需要醬油,張師傅需要醋,此時呢,徐師傅在拿著醋,張師傅在拿著醬油,2個人就等著對方誰先放下手裡這個東西。一直不放就會一直等下去。

徐師傅
張師傅
死鎖

這樣就造成死鎖了,程序進行不下去了。

死鎖的發生必須滿足以下四個條件:

互斥條件:一個資源每次只能被一個進程使用。請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關係。

避免死鎖最簡單的方法就是阻止循環等待條件,將系統中所有的資源設置標誌位、排序,規定所有的進程申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。小編這裡拿調整鎖的範圍來避免死鎖

縮小死鎖範圍

除了死鎖還有一種情況就是活鎖,這個可能大家不是經常被問到,活鎖和死鎖類似,不同之處在於處於活鎖的線程或進程的狀態是不斷改變的,活鎖可以認為是一種特殊的飢餓。一個現實的活鎖例子是兩個人在狹小的走廊碰到,兩個人都試著避讓對方好讓彼此通過,但是因為避讓的方向都一樣導致最後誰都不能通過走廊。簡單的說就是,活鎖和死鎖的主要區別是前者進程的狀態可以改變但是卻不能繼續執行。這裡在拿張師傅和徐師傅為例,比如張師傅和徐師傅都要進廚房做飯,正趕上做飯點,張師傅認為徐師傅應該先做,徐師傅任務張師傅先做,就這樣來回謙讓,最後誰也沒做。

徐師傅
張師傅
執行
結果

活鎖發生的條件:

1、消息重試。當某個消息處理失敗的時候,一直重試,但重試由於某種原因,比如消息格式不對,導致解析失敗,而它又被重試,這種時候一般是將不可修復的錯誤不要重試,或者是重試次數限定。

2、相互協作的線程彼此響應從而修改自己狀態,導致無法執行下去。比如兩個很有禮貌的人在同一條路上相遇,彼此給對方讓路,但是又在同一條路上遇到了。互相之間反覆地避讓下去,這種時候可以選擇一個隨機退讓,使得具備一定的隨機性。

相關焦點

  • 預測讀寫鎖的死鎖問題,居然有人做到了?
    在最終成功修復了這幾個內核故障後,終於有一些時間靜下來去深入思考死鎖發生的原因和如何去檢測和預測死鎖。隨著對這個問題的深入研究,我相繼做出了一些內核死鎖預測方面的算法優化和算法設計工作,其中部分已經被 Linux 內核接收,其他還在評審階段。在這裡我和大家分享其中的一個比較重要的工作:一個通用的讀寫鎖的死鎖預測算法。
  • 這有一把鑰匙,打開MySQL死鎖問題!
    由於同時發生的,那麼他們就死鎖了。問題是:1,場景如第一行,是同時互相轉錢,我這樣的後臺資料庫操作邏輯對不對?2,如果是對的,死鎖是否會發生?如果是不對的,該如何設計後臺實現?3,如果死鎖會發生,該如何避免,mysql的事務自動會處理(有人說會自動處理),那我能不能代碼的設計上,避免這種死鎖的情況?1. 這種情況是有可能導致死鎖的,A在等待B釋放資源,B在等待A釋放資源,相互等待資源,造成死鎖。
  • 一個線上SQL死鎖異常分析:深入了解事務和鎖
    阿里妹導讀:引發死鎖的原因是什麼?如何避免?
  • 並行編程中的「鎖」難題
    在並行程序中,鎖的使用會主要會引發兩類難題:一類是諸如死鎖、活鎖等引起的多線程Bug;另一類是由鎖競爭引起的性能瓶頸。本文將介紹並行編程中因為鎖引發的這兩類難題及其解決方案。死鎖和活鎖然而,鎖的使用非常容易導致多線程Bug,最常見的莫過於死鎖和活鎖。從原理上講,死鎖的產生是由於兩個(或多個)線程在試圖獲取正被其他線程佔有的資源時造成的線程停滯。
  • MySQL死鎖分析與解決之路
    來自:貝殼DBA咱們使用 MySQL 大概率上都會遇到死鎖問題,這實在是個令人非常頭痛的問題。本文將會對死鎖進行相應介紹,對常見的死鎖案例進行相關分析與探討,以及如何去儘可能避免死鎖給出一些建議。--什麼是死鎖 --死鎖是並發系統中常見的問題,同樣也會出現在資料庫MySQL的並發讀寫請求場景中。
  • MySQL REPLACE死鎖問題深入剖析
    同樣的,若只將此題理解成REPLACE會拆成DELETE+INSERT也是不正確的,因為REPLACE在鎖的處理上並非完全的等同於DELETE + INSERT。雖然同樣可以模擬出死鎖,然而兩者輸出的結果是不一樣的。此外,這個死鎖只需要並發度為2就能出線死鎖,又進一步提升了其逼格。
  • Java多線程之死鎖問題
    Java多線程之死鎖定義多個線程各自佔有一些共享的資源,並且互相等待,直到獲取到對方線程佔有的資源本身才能夠繼續運行,而導致了兩個或者兩個以上的線程同時在無休止地等待對方釋放資源,從而這些線程都處於停止狀態。某一個同步塊同時擁有兩個以上對象的鎖時,就可能發生死鎖的情況。
  • Linux 自旋鎖spinlock,教你如何把ubuntu弄死鎖
    自旋鎖的使用在linux kernel的實現中,經常會遇到這樣的場景:共享數據被中斷上下文和進程上下文訪問,該如何保護呢?自旋鎖可以在中斷上下文中使用,但是試想一個場景:一個線程獲取了一個鎖,但是被中斷處理程序打斷,中斷處理程序也獲取了這個鎖(但是之前已經被鎖住了,無法獲取到,只能自旋),中斷無法退出,導致線程中後面釋放鎖的代碼無法被執行,導致死鎖。(如果確認中斷中不會訪問和線程中同一個鎖,其實無所謂)。
  • Mysql資料庫update操作死鎖問題分析
    簡介問題是這樣的,我負責的一個線上模塊的功能是給裝有我們產品APP的手機設備根據業務功能打上特殊的推送標籤。每個設備有多個不同的標籤,每個標籤下包括很多設備。由於用戶在使用app時會觸發很多邏輯,隨時都可能有對標籤的增刪。
  • MySQL中悲觀鎖和樂觀鎖到底是什麼?
    索引和鎖是資料庫中的兩個核心知識點,隔離級別的實現都是通過鎖來完成的 按照鎖顆粒對鎖進行劃分 ? 鎖用來對數據進行鎖定,我們可以從鎖定對象的粒度大小來對鎖進行劃分,分別為行鎖、頁鎖和表鎖。
  • Linux的strace命令跟蹤線程死鎖
    基本用法:sudo strace -p 進程號如果一個線程遞歸獲取同一個鎖,或者多個線程以不同的順序獲取多個鎖,那麼就會導致至少有一個線程在持有鎖的情況下再次等待在一個鎖上(持有的鎖和等待的鎖可能相同或不同),導致死鎖(deadlock)。
  • InnoDB加鎖實驗
    I.實驗目的通過對MySQL中各種讀寫操作的加鎖情況的分析, 解構死鎖場景, 輔助分析死鎖出現的原因, 以更高效地解決死鎖問題. II. 普通記錄鎖就是之鎖定一個索引的entry, 而gap lock會鎖定一個開區間(a,b), next-key鎖是record lock和gap lock的聚合, 鎖定一個左開右閉的區間, (ab]. 這3種鎖如何鎖定, 如何確定範圍, 會在後面的試驗中講到, 這裡就先不舉例子了. III.
  • 24張圖帶你徹底理解Java中的21種鎖
    、reentrantlock(false)8共享鎖ReentrantReadWriteLock中讀鎖9獨佔鎖synchronized、vector、hashtable、ReentrantReadWriteLock中寫鎖10重量級鎖synchronized11輕量級鎖鎖優化技術12偏向鎖鎖優化技術13分段鎖concurrentHashMap14互斥鎖synchronized15同步鎖synchronized16
  • Java程式設計師面試中的多線程問題
    調用 object.wait ()時,線程先要獲取這個對象的對象鎖,當前線程必須在鎖對象保持同步,把當前線程添加到等待隊列中,隨後另一線程可以同步同一個對象鎖來調用 object.notify (),這樣將喚醒原來等待中的線程,然後釋放該鎖。基本上 wait ()/notify ()與 sleep ()/interrupt ()類似,只是前者需要獲取對象鎖。
  • Redis如何實現分布式鎖?
    文章已收錄Github精選,歡迎Star:https://github.com/yehongzhi前言如果在一個分布式系統中,我們從資料庫中讀取一個數據,然後修改保存,這種情況很容易遇到並發問題。因為讀取和更新保存不是一個原子操作,在並發時就會導致數據的不正確。
  • 共享鎖、排他鎖、互斥鎖、悲觀鎖、樂觀鎖、行鎖、表鎖、頁面鎖、不可重複讀、丟失修改、讀髒數據
    開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,並發度也最高。表級鎖: 表級鎖是 MySQL 中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分 MySQL 引擎支持。最常使用的 MyISAM 與 InnoDB 都支持表級鎖定。
  • Lock鎖 精講
    建議避免混淆,除非在自己的實現中使用,否則不要以這種方式使用Lock實例。4.內存同步       所有Lock實現必須強制執行與內置監視器鎖所提供的相同的內存同步語義,如Java語言規範中所述 :       不成功的鎖定和解鎖操作以及可重入的鎖定/解鎖操作不需要任何內存同步效果。
  • Node.js 中實踐基於 Redis 的分布式鎖實現
    在一些分布式環境下、多線程並發編程中,如果對同一資源進行讀寫操作,避免不了的一個就是資源競爭問題,通過引入分布式鎖這一概念,可以解決數據一致性問題
  • Java 中15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖,樂觀鎖,分段鎖,自旋鎖等等
    ,第二次調用自旋的時候就會產生死鎖,這個鎖就不是可重入的,而實際上同一個線程不必每次都去釋放鎖再來獲取鎖,這樣的調度切換是很耗資源的。private volatile int state來計數重入次數,避免了頻繁的持有釋放操作,這樣既提升了效率,又避免了死鎖。
  • 手把手教你實現基於Redis的分布式鎖
    單機多進程的情況,在Python語言中,可以使用 multiprocessing 的 Lock 對象來保證多進程安全。多機多進程部署的情況,需要依賴一個第三方組件(存儲鎖對象)來實現一個分布式的同步鎖。2. 分布式鎖的必要條件本文主要介紹第三種場景下基於Redis如何實現分布式鎖。現在我們來看看實現一個分布式鎖的必要條件有哪些?