什麼是死鎖?如何解決死鎖?
死鎖是指兩個或兩個以上的程式在執行過程中,由於競爭資源或者由於彼此通訊而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的程式稱為死鎖程式。產生死鎖的原因,主要包括:
-
系統資源不足;
-
程式執行的順序有問題;
-
資源分配不當等。
如果系統資源充足,程式的資源請求都能夠得到滿足,那麼死鎖出現的可能性就很低;否則,
就會因爭奪有限的資源而陷入死鎖。其次,程式執行的順序與速度不同,也可能產生死鎖。產生死鎖的四個必要條件:
-
互斥條件:一個資源每次只能被一個程式使用。
-
請求與保持條件:一個程式因請求資源而阻塞時,對已獲得的資源保持不放。
-
不剝奪條件:程式已獲得的資源,在末使用完之前,不能強行剝奪。
-
迴圈等待條件:若干程式之間形成一種頭尾相接的迴圈等待資源關係。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
如何解決死鎖?
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,我們就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、程式排程等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配演算法,避免程式永久佔據系統資源,這就是避免、預防和解決死鎖的最佳實踐。此外,也要防止程式在處於等待狀態的情況下佔用資源。因此,對資源的分配要給予合理的規劃。
用下面一段死鎖的程式碼來理解吧
public class DeadLock { public static final String LOCK_1 = "lock1"; public static final String LOCK_2 = "lock2"; public static void main(String[] args) { Thread threadA = new Thread(() -> { try { while (true) { synchronized (DeadLock.LOCK_1) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock1"); Thread.sleep(1000); synchronized (DeadLock.LOCK_2) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock2"); } } } } catch (Exception e) { e.printStackTrace(); } }); Thread threadB = new Thread(() -> { try { while (true) { synchronized (DeadLock.LOCK_2) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock2"); Thread.sleep(1000); synchronized (DeadLock.LOCK_1) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock1"); } } } } catch (Exception e) { e.printStackTrace(); } }); threadA.start(); threadB.start(); } }
如上述程式碼所示,我們啟動了兩個執行緒,在每個執行緒中都要獲得DeadLock.LOCK_1和DeadLock.LOCK_2,其中
-
threadA,先獲取DeadLock.LOCK_1,再獲取DeadLock.LOCK_2
-
threadB,先獲取DeadLock.LOCK_2,再獲取DeadLock.LOCK_1
這樣,當threadA獲取到DeadLock.LOCK_1之後,就要去獲取DeadLock.LOCK_2,而DeadLock.LOCK_2則是先被threadB獲取了,因此threadA就需要等待threadB釋放DeadLock.LOCK_2之後才能繼續執行;但是threadB在獲取到DeadLock.LOCK_2之後,卻是在等待threadA釋放DeadLock.LOCK_1,因此這就形成了“迴圈等待條件”,從而形成了死鎖。想要解決這個死鎖很簡單,我們只需要讓threadA和threadB獲取DeadLock.LOCK_1和DeadLock.LOCK_2的順序相同即可,例如:
public class DeadLock { public static final String LOCK_1 = "lock1"; public static final String LOCK_2 = "lock2"; public static void main(String[] args) { Thread threadA = new Thread(() -> { try { while (true) { synchronized (DeadLock.LOCK_1) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock1"); Thread.sleep(1000); synchronized (DeadLock.LOCK_2) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock2"); } } } } catch (Exception e) { e.printStackTrace(); } }); Thread threadB = new Thread(() -> { try { while (true) { synchronized (DeadLock.LOCK_1) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock1"); Thread.sleep(1000); synchronized (DeadLock.LOCK_2) { System.out.println(Thread.currentThread().getName() + " 鎖住 lock2"); } } } } catch (Exception e) { e.printStackTrace(); } }); threadA.start(); threadB.start(); } }
除此之外,還有一種解決方法,那就是讓DeadLock.LOCK_1和DeadLock.LOCK_2的值相同,例如:
public static final String LOCK_1 = "lock"; public static final String LOCK_2 = "lock";
這是為什麼呢?因為字串有一個常量池,如果不同的執行緒持有的鎖是具有相同字元的字串鎖時,那麼兩個鎖實際上就是同一個鎖。
本文來源於:奈學開發者社群,如有侵權請聯絡我刪除~
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69976011/viewspace-2710964/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 面試:什麼是死鎖,如何避免或解決死鎖;MySQL中的死鎖現象,MySQL死鎖如何解決面試MySql
- 面試官:什麼是死鎖?怎麼排查死鎖?怎麼避免死鎖?面試
- java中死鎖是什麼Java
- SQ死鎖及死鎖的解決
- 你真的理解什麼是死鎖嗎?
- Java鎖——死鎖Java
- MySQL 死鎖解決MySql
- MySQL解決死鎖MySql
- 死鎖
- oracle 死鎖表解決方法Oracle
- 殺死Oracle死鎖程式Oracle
- 死鎖分析
- oracle 死鎖Oracle
- 檢視oracle死鎖程式並結束死鎖Oracle
- 例項詳解 Java 死鎖與破解死鎖Java
- MySQL死鎖系列-線上死鎖問題排查思路MySql
- 作業系統(5) 死鎖的概念 死鎖產生的必要條件 死鎖的處理策略 預防死鎖 避免死鎖 死鎖的檢測和解除 銀行家演算法作業系統演算法
- MySQL 死鎖和鎖等待MySql
- 鎖賦值給其他變數為什麼會死鎖呢?賦值變數
- 死鎖檢測及解決
- 遭遇ITL死鎖
- GCD 死鎖原因GC
- 死鎖案例分析
- HashMap死鎖分析HashMap
- SQL Server死鎖SQLServer
- 死鎖-舉例
- 這種死鎖怎麼理解
- MySQL:一個死鎖分析 (未分析出來的死鎖)MySql
- MySQL死鎖分析與解決之路MySql
- 解決Oracle死鎖的快捷方法Oracle
- oracle死鎖測試與解決Oracle
- 解決Oracle資料庫死鎖Oracle資料庫
- java多執行緒中的死鎖、活鎖、飢餓、無鎖都是什麼鬼?Java執行緒
- mysql行鎖和死鎖檢測MySql
- SQLServer的死鎖分析(1):頁鎖SQLServer
- Mysql 兩階段鎖和死鎖MySql
- PostgreSQL死鎖相關SQL
- Java 中的死鎖Java