2016-06-22 100 views
2

我有以下三個類。在java代碼中獲取死鎖

BaseClass.java

public class BaseClass { 

    static { 
     load(); 
    } 

    public static void init() { 
     System.out.println("base init"); 
    } 

    private static void load() { 
     System.out.println("In load method of base class"); 
     DerivedClass dc = new DerivedClass(); 
     System.out.println("Object creation done."); 
    } 

} 

DerivedClass.java

public class DerivedClass extends BaseClass { 

    public DerivedClass() { 
     System.out.println("derived class constructor"); 
    } 

    public static boolean isSynthetic(String _attr) { 
     return true; 
    } 
} 

Helper.java

public class Helper { 

    public static void main(String[] args) { 
     Thread t = new Thread() { 
      public void run() { 
       BaseClass.init(); 
      }; 
     }; 
     t.start(); 
     System.out.println("calling static method of derived class.."); 
     System.out.println(DerivedClass.isSynthetic("test")); 
    } 

} 

當我執行從Helper.java主要方法,我得到以下輸出 -

調用派生類的靜態方法..

在基類

的負載方法此執行之後是停止但過程仍在運行。 所以看起來有一些僵局,但我不明白這是爲什麼。 需要幫助。

+0

下面的鏈接回答你的問題。 [http://stackoverflow.com/questions/10698516/behavior-of-static-blocks-with-inheritance](http://stackoverflow.com/questions/10698516/behavior-of-static-blocks-with-inheritance ) –

回答

2

當第一次引用BaseClass時,類加載器啓動並想要設置該類以供使用。所以它加載類,並開始靜態初始化塊

static { 
    load(); 
} 

這將調用load - 方法有你嘗試創建DerivedClass類型的對象。這將首先嚐試調用super()-構造器,即類BaseClass的方法 - 但BaseClass尚未完全初始化,因爲它的靜態初始化器尚未完成=>死鎖。

編輯: 根據您的意見,我做了一些更多的研究。事實上,事情並不像我想象的那麼簡單。 JVM能夠處理遞歸初始化,所以在單線程情況下沒有問題。有關類初始化過程的描述可以在JVM規範的5.5節中找到。

這裏的罪魁禍首實際上是兩個初始化過程之間的競爭條件。

線程1達到DerivedClass.isSynthetic("test"),並開始初始化DerivedClass

同時線程2到達BaseClass.init()並開始初始化BaseClass。當初始化DerivedClass線程1認識到它必須初始化超類。由於線程2已經在進行BaseClass的初始化,線程1必須等待它完成。當初始化線程2達到DerivedClass dc = new DerivedClass();。由於線程1已經在進行DerivedClass的初始化,所以線程2必須等待它完成。

所以實際上這是一個典型的死鎖,其中兩個線程嘗試按不同順序輸入兩個關鍵代碼路徑(「類X的初始化」)(BaseClass-> DerivedClass vs.DerivedClass-> BaseClass)並最終等待對方。

在適當的地方添加一些Thread.sleep(100);也會告訴你這是一個真正的競賽條件。在我的測試過程中,有時程序完成成功,儘管在初始化過程中存在循環依賴。

+0

你的解釋似乎是可能的,但是爲什麼'System.out.println(DerivedClass.isSynthetic(「test」));'這裏派生類的靜態方法也處於死鎖狀態。當我刪除派生類的靜態方法的調用,然後執行工作正常,我得到的輸出爲:
調用 在基類 派生類構造函數 完成對象創建。 base init –

+0

@Rahulkhandelwal你說得對,JVM比我想象的更復雜。我爲真正的原因添加了一些解釋。 –

+0

感謝您的解釋。這真的很有幫助。 –