2014-10-28 52 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