Java面試問題,如何避免Java線程中的死鎖?

如何避免Java中的死鎖?是流行的Java面試問題之一,也是多線程的流行話題之一。儘管問題看起來很簡單,可是一旦深刻,大多數Java開發人員就會陷入困境。面試

面試問題以「什麼是死鎖?」當兩個或多個線程正在等待彼此釋放所需資源(鎖定)並陷入無限時間的阻塞時,這種狀況稱爲死鎖,它只會在多任務或多線程的狀況下發生。多線程

如何檢測Java中的死鎖? 雖然這可能有不少答案,但個人版本是,若是我看到嵌套的同步塊,或者從其餘同步方法調用一個同步方法,或者試圖在不一樣的對象上得到鎖,那麼若是開發人員不是很是當心,就極可能出現死鎖。工具

另外一種方法是在運行應用程序時發現線程被鎖定,嘗試使用線程轉儲,在Linux中能夠經過命令「kill -3」來實現,這將打印應用程序日誌文件中全部線程的狀態,就能夠看到哪一個線程被鎖定在哪一個對象上。ui

也可使用fastthread等工具分析線程轉儲,上傳你的線程轉儲並分析它。spa

另外一種方法是使用jConsole/VisualVM,它將準確地顯示哪些線程被鎖定,以及在哪一個對象上。線程

編寫一個會致使死鎖的Java程序 一旦回答了前面的問題,他們可能會要求你編寫致使Java死鎖的代碼3d

這是個人一個版本日誌

/**code

  • Java程序經過強制循環等待來建立死鎖
  • @author WINDOWS 8

*/ public class DeadLockDemo {cdn

/*

  • T此方法請求兩個鎖,首先是String,而後是Integer */ public void method1() { synchronized (String.class) { System.out.println("Aquired lock onString.classobject");

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釋放整數鎖定繼續進行。

相關文章
相關標籤/搜索