2014-10-28 55 views
1

在WebLogic應用程序之後,已經幾個星期運行良好,我突然得到一個異常:Java ClassLoader問題或併發錯誤?

<Oct 25, 2014 9:31:11 PM EDT> <Error> <HTTP> <BEA-101020> 
    <[[email protected][app:whatever3000 module:whatever3000.war path: 
    spec-version:2.5]] Servlet failed with Exception 
    java.lang.ExceptionInInitializerError 

後,該應用程序是完全NoClassDefFoundError直到倒閉的應用服務器重新啓動。

完整堆棧跟蹤顯示問題的來源是在靜態初始化器中的ConcurrentModificationException

具體的當量/最小化代碼如下:

package a; 
import b; 

public class Whatever { 
    void doIt() 
    { 
     Password p = new Password(); 
    } 
} 

package b; 

public final class Password implements Serializable 
{ 
    private static final int PARAM1 = CommonStuff.someStaticMethod(); 
    ... 
} 

import java.util.Properties; 

public class CommonStuff 
{ 
    private static Properties prp = new Properties(); 

    static { 
     CommonStuff.load(); 
    } 

    public static void load() 
    { 
     prp.putAll(System.getProperties()); <---FAIL 

這是異常原因:應用程序時,WebLogic運行期間

java.util.ConcurrentModificationException 
     at java.util.Hashtable$Enumerator.next(Hashtable.java:1017) 
     at java.util.Hashtable.putAll(Hashtable.java:469) 
     at b.CommonStuff.load(CommonStuff.java:55) 
     at b.CommonStuff.<clinit>(CommonStuff.java:77) 
     at b.Password.<clinit>(Password.java:44) 
     at a.doIt(Whatever.java:99) 

因此,似乎在某些點決定從package b重新加載類,但是當靜態塊運行時,它發現Properties對象已被修改。

我不知道它是否被同時調用,或者它是否被多次調用。可能是Properties對象是應用程序第一次加載時創建的原始實例,CommonStuff類的重新加載嘗試再次調用putAll()

它是否有助於如果我這樣做:

private static Properties prp = null; 

static { 
    CommonStuff.prp = new Properties(); 
    CommonStuff.load(); 
} 

我不能只是嘗試的東西盲目,因爲它在生產應用程序在一個巨大的公司。所以我試圖瞭解我要出錯的地方以及如何在半夜重新加載類時初始化這些變量。

任何想法?

這可能是WebLogic ClassLoader問題嗎?

回答

2

在此類初始化之前,類/實例無法訪問某個類的成員。因此,在靜態構造函數返回之前,沒有人可以訪問新創建的prp。在static {}塊內移動prp初始值設定項沒有區別。 「舊」和「新」prp「舊」prp沒有以任何方式連接(因爲「舊」和「新」CommonStuff是JVM不同的類)。這一切都使prp的併發修改看起來很奇怪的可能性。

我相信原因是在另一個地方。注意堆棧跟蹤的第一行:異常由HashtableEnumerator引發。這裏是putAll方法的代碼(如JDK 8,可能沒有很多年變化):

for (Map.Entry<? extends K, ? extends V> e : t.entrySet()) 
    put(e.getKey(), e.getValue()); 

這裏是拋出一個異常的Enumerator - 這是不是prp,這是爭論的Enumerator

因此,例外情況與prp不相關,但與相關,由System.getProperties()返回。原因是迭代系統屬性映射不是線程安全的。看來另一個線程正在同時修改它。

您需要以不同方式初始化prp。我認爲clone()是最簡單的方法。

+0

這看起來可能是原因。其他人獨立地有相同的診斷。我已經添加了clone(),我們將在接下來的幾周內看到它是否有效。謝謝。 – squarewav 2014-10-31 05:50:38