如何避免Java中的死鎖?是流行的Java面試問題之一,也是多線程的流行話題之一。儘管問題看起來很簡單,可是一旦深刻,大多數Java開發人員就會陷入困境。面試
面試問題以「什麼是死鎖?」當兩個或多個線程正在等待彼此釋放所需資源(鎖定)並陷入無限時間的阻塞時,這種狀況稱爲死鎖,它只會在多任務或多線程的狀況下發生。多線程
如何檢測Java中的死鎖? 雖然這可能有不少答案,但個人版本是,若是我看到嵌套的同步塊,或者從其餘同步方法調用一個同步方法,或者試圖在不一樣的對象上得到鎖,那麼若是開發人員不是很是當心,就極可能出現死鎖。工具
另外一種方法是在運行應用程序時發現線程被鎖定,嘗試使用線程轉儲,在Linux中能夠經過命令「kill -3」來實現,這將打印應用程序日誌文件中全部線程的狀態,就能夠看到哪一個線程被鎖定在哪一個對象上。ui
也可使用fastthread等工具分析線程轉儲,上傳你的線程轉儲並分析它。spa
另外一種方法是使用jConsole/VisualVM,它將準確地顯示哪些線程被鎖定,以及在哪一個對象上。線程
編寫一個會致使死鎖的Java程序 一旦回答了前面的問題,他們可能會要求你編寫致使Java死鎖的代碼3d
這是個人一個版本日誌
/**code
*/ public class DeadLockDemo {cdn
/*
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.classobject");
synchronized (String.class) { System.out.println("Aquired lock on String.class object"); } } } } 若是method1()和method2()都將被兩個或多個線程調用,那麼死鎖的可能性很大,若是線程1在執行method1()時獲取Sting對象上的鎖,而線程2在執行method2()時獲取Integer對象上的鎖,那麼線程2將等待對方釋放Integer和String上的鎖以繼續執行,而這永遠不會發生
此圖準確演示了咱們的程序,其中一個線程持有一個對象的鎖並等待其餘線程持有的其餘對象鎖。
Java面試問題,如何避免Java線程中的死鎖? 你能夠看到線程1想要對線程2持有的對象2的鎖定,而線程2想要對線程1持有的對象1進行鎖定。因爲沒有線程願意放棄,因此存在死鎖而且Java程序卡住了。
如何避免Java中的死鎖 如今面試官來到最後一部分,這是我認爲最重要的部分之一; 你如何修復代碼中的死鎖?或者如何避免Java中的死鎖?
若是仔細查看了上面的代碼,那麼你可能已經發現死鎖的真正緣由不是多線程,而是它們請求鎖定的方式,若是提供有序訪問,則問題將獲得解決。
這是個人固定版本,它避免了因爲沒有搶佔的無效循環等待致使的死鎖,這是須要死鎖的四個條件之一。
public class DeadLockFixed { /**
兩種方法如今都以相同的順序請求鎖定,首先是Integer,而後是String。
也能夠完成反向,例如第一個String而後是Integer
二者都會解決問題,只要兩種方法都請求鎖定
按照一致的順序 */ 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釋放整數鎖定,一樣,即便線程B保持字符串鎖定,線程A也不會被阻止,由於如今線程B不會指望線程A釋放整數鎖定繼續進行。