併發編程之死鎖

 
產生死鎖的4個必要條件
  • 互斥條件:在一段時間內某資源僅爲一個線程所佔有
  • 不可剝奪條件:線程所得到的資源在未使用完畢以前,不能被其餘線程強行奪走
  • 請求和保持條件:線程已經保持了至少一個資源,但又提出了新的資源請求,而該資源已被其餘線程佔有
  • 循環等待條件:存在一種線程資源的循環等待鏈,鏈中每個線程已得到的資源同時被鏈中下一個線程所請求。

 

產生死鎖的狀況數據庫

  • 多個鎖的交叉(交叉鎖)
                交叉鎖引發的線程會進入BLOCKED狀態,CPU資源棧用不高,很容易藉助工具發現
                情景描述:線程A持有鎖1,等待獲取鎖2;線程B持有鎖2,等待獲取鎖1。
private final static Object MUTEX_READ = new Object();
private final static Object MUTEX_WRITE = new Object();
public void read(){
    synchronized (MUTEX_READ) {
        synchronized (MUTEX_WRITE) {
        }
    }
}
public void write(){
    synchronized (MUTEX_WRITE) {
        synchronized (MUTEX_READ) {
        }
    }
}
  • 內存不足
  • 一問一答式的數據交換
            服務器開啓了某個端口,等待客戶端的訪問。客戶端發送請求後等待服務器的響應,服務器由於某種緣由錯過了客戶端的請求,讓在等待請求。此時,服務端可客戶端都在等待對方發送數據。
  • 數據庫鎖
            好比某個線程執行了for update語句後退出了事務,其餘線程訪問的時候就會陷入死鎖
  • 文件鎖
            獲取文件鎖的線程意外退出,其它線程沒法獲取該文件鎖會進入死鎖。
  • 死循環引發的死鎖【系統假死,查看堆棧信息沒法發現任何死鎖跡象,CPU佔有率居高不下,是最爲致命以及最難排查的死鎖現象】

 

處理死鎖的方法服務器

 經過設置某些限制條件,去破壞產生死鎖的四個必要條件中的一個或幾個條件,來防止死鎖的發生。【在死鎖產生的四個必要條件中,「互斥條件」是沒法破壞的,破壞「互斥條件」會形成結果的不可再現性】數據結構

  • 破壞「不可剝奪條件」
        容許對資源實行搶奪。
        方法一:若是佔有某些資源的一個線程進行進一步資源請求被拒絕,則該線程必須釋放它最初佔有的資源【若是有須要,可再次請求這些資源和另外的資源】。
        方法二:容許優先級高的線程搶佔優先級低的線程的資源。
  • 破壞「請求和保持條件」
       在系統中不容許進程在已得到某種資源的狀況下,申請其餘資源。
          方法一:採用「 一次性分配」方案,即:建立進程時,要求它申請所需的所有資源,系統或知足其全部要求,或什麼也不給它。
          方法二:要求每一個進程提出新的資源申請前,釋放它所佔有的資源。
  • 破壞「循環等待條件」
          將系統中的全部資源進行編號,線程必須按照順序申請資源。
 
避免死鎖的處理方式
  • 加鎖順序:給全部的鎖排序,線程只能按照升序(降序)的獲取鎖。【破壞循環等待條件】
  • 加鎖超時:給線程設置獲取鎖的最大等待時間,若是超時則放棄對該鎖的請求並釋放已佔有的鎖,等待一段時間後再次請求。【破壞請求和保持條件】
  • 死鎖檢測
            主要是針對那些不可能實現按序加鎖而且鎖超時也不可行的場景。每當一個線程請求或者得到了鎖,會在線程和鎖相關的數據結構中將其記下。
            線程A等待線程B,線程B等待線程C,線程C等待線程D,線程D又在等待線程A。線程A爲了檢測死鎖,它須要遞進地檢測全部被B請求的鎖。從線程B所請求的鎖開始,線程A找到了線程C,而後又找到了線程D,發現線程D請求的鎖被線程A本身持有着。這是它就知道發生了死鎖。
 
檢測和解除死鎖
 
    因爲操做系統有併發、共享以及隨機性等特色,經過預防和避免的手段達到排除死鎖的目的是很困難的。一種簡便的方法是系統爲進程分配資源時,不採起任何限制性措施,可是提供了檢測和解脫死鎖的手段:能發現死鎖並從死鎖狀態中恢復出來。所以,在實際的操做系統中每每採用死鎖的檢測和解除方法來排除死鎖。
        死鎖檢測和解除是指系統設有專門的機制,當死鎖發生時,該機制可以檢測到死鎖發生的位置和緣由,並能經過外力破壞死鎖發生的必要條件,從而使得併發進程從死鎖狀態中恢復出來。
  • 解除死鎖
            1) 資源剝奪法:掛起某些死鎖進程,並釋放它的資源,將這些資源分配給其餘的死鎖進程。【但應防止被掛起的進程長時間得不到資源,而處於資源匱乏的狀態】
            2) 撤銷線程法:強制撤銷部分、甚至所有死鎖線程。【撤銷的原則能夠按進程優先級和撤銷進程代價的高低進行】
            3) 進程回退法:讓一(多)個線程回退到足以迴避死鎖的地步【要求系統保持進程的歷史信息,設置還原點】
相關文章
相關標籤/搜索