死鎖
在JDK1.7以前,java.lang.ClassLoader的一些核心方法是被synchronized修飾的,比如loadClass,以下摘自JDK6下java.lang.ClassLoader的部分方法:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {...} private synchronized Class loadClassInternal(String name) throws ClassNotFoundException {...} private synchronized void checkCerts(String name, CodeSource cs) {...} private static synchronized void initSystemClassLoader() {...}
由於方法被synchronized修飾,當BundleA加載PackageB時,要先鎖定BundleA類加載器的實例對象,然后將請求委派給BundleB的類加載器處理,但如果這時BundleB也正好想要加載packageA的類,就需要先鎖定BundleB類加載器再去請求BundleA的加載器處理,這樣兩個加載器都在等待對方處理自己的請求,但有各自又都持有己方的鎖,就造成了死鎖狀態。
BundleA和BundleB相互依賴
解決
在JDK1.7之后對這個問題做出了優化,可以以手動注冊的方式將類加載標識為具備並行能力,之后在加載類的時候棄用了方法級別synchronized的方式,改為了為每個要加載的class文件(全路徑名)都對應一個Object對象鎖。加鎖的時候如果加載器具備並行能力,那么就不再對類加載器進行加鎖,而是找到加載類文件對應的Object鎖進行加鎖操作。