您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關如何檢測并避免 Java 中的死鎖,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
如果你沒有參與過多線程并發 Java 應用程序的編碼,你可能會失敗。
這是 Java 面試 的熱門問題之一, 也是多線程的編程中的重口味之一, 主要在招高級程序員時容易被問到, 且有很多后續問題。
盡管問題看起來非常基本, 但大多數 Java 開發人員一旦你開始深入, 就會陷入困境。
當兩個或多個線程在等待彼此釋放所需的資源(鎖定)并陷入無限等待即是死鎖。它僅在多任務或多線程的情況下發生。
雖然這可以有很多答案, 但我的版本是首先我會看看代碼, 如果我看到一個嵌套的同步塊,或從一個同步的方法調用其他同步方法, 或試圖在不同的對象上獲取鎖, 如果開發人員不是非常小心,就很容易造成死鎖。
另一種方法是在運行應用程序時實際鎖定時找到它, 嘗試采取線程轉儲,在 Linux 中,你可以通過kill -3命令執行此操作, 關注公眾號小黃鴨編程社區,回復關鍵字手冊,獲取最新開發手冊,這將打印應用程序日志文件中所有線程的狀態, 并且你可以看到哪個線程被鎖定在哪個線程對象上。
你可以使用 fastthread.io 網站等工具分析該線程轉儲, 這些工具允許你上載線程轉儲并對其進行分析。
另一種方法是使用 jConsole 或 VisualVM, 它將顯示哪些線程被鎖定以及哪些對象被鎖定。
如果你有興趣了解故障排除工具和分析線程轉儲的過程, 我建議你看看 Uriah Levy 在多元視覺(PluraIsight)上《分析 Java 線程轉儲》課程。旨在詳細了解 Java 線程轉儲, 并熟悉其他流行的高級故障排除工具。
一旦你回答了前面的問題,他們可能會要求你編寫代碼,這將導致Java死鎖。
/**
* Java 程序通過強制循環等待來創建死鎖。
*/
public class DeadLockDemo {
/*
* 此方法請求兩個鎖,第一個字符串,然后整數
*/
public void method1() {
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
}
}
}
/*
* 此方法也請求相同的兩個鎖,但完全
* 相反的順序,即首先整數,然后字符串。
* 如果一個線程持有字符串鎖,則這會產生潛在的死鎖
* 和其他持有整數鎖,他們等待對方,永遠。
*/
public void method2() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
}
如果 method1() 和 method2() 都由兩個或多個線程調用,則存在死鎖的可能性, 因為如果線程 1 在執行 method1() 時在 Sting 對象上獲取鎖, 線程 2 在執行 method2() 時在 Integer 對象上獲取鎖, 等待彼此釋放 Integer 和 String 上的鎖以繼續進行一步, 但這永遠不會發生。
此圖精確演示了我們的程序, 其中一個線程在一個對象上持有鎖, 并等待其他線程持有的其他對象鎖。
你可以看到, Thread1 需要 Thread2 持有的 Object2 上的鎖,而 Thread2 希望獲得 Thread1 持有的 Object1 上的鎖。由于沒有線程愿意放棄, 因此存在死鎖, Java 程序被卡住。
其理念是, 你應該知道使用常見并發模式的正確方法, 如果你不熟悉這些模式,那么 Jose Paumard 《應用于并發和多線程的常見 Java 模式》是學習的好起點
現在面試官來到最后一部分, 在我看來, 最重要的部分之一; 如何修復代碼中的死鎖?或如何避免Java中的死鎖?
如果你仔細查看了上面的代碼,那么你可能已經發現死鎖的真正原因不是多個線程, 而是它們請求鎖的方式, 如果你提供有序訪問, 則問題將得到解決。
下面是我的修復版本,它通過避免循環等待,而避免死鎖, 而不需要搶占, 這是需要死鎖的四個條件之一。
public class DeadLockFixed {
/**
* 兩種方法現在都以相同的順序請求鎖,首先采用整數,然后是 String。
* 你也可以做反向,例如,第一個字符串,然后整數,
* 只要兩種方法都請求鎖定,兩者都能解決問題
* 順序一致。
*/
public void method1() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
public void method2() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
}
現在沒有任何死鎖,因為兩種方法都按相同的順序訪問 Integer 和 String 類文本上的鎖。
因此,如果線程 A 在 Integer 對象上獲取鎖, 則線程 B 不會繼續, 直到線程 A 釋放 Integer 鎖, 即使線程 B 持有 String 鎖, 線程 A 也不會被阻止, 因為現在線程 B 不會期望線程 A 釋放 Integer 鎖以繼續。
看完上述內容,你們對如何檢測并避免 Java 中的死鎖有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。