[英]Java ClassLoader Issue or Concurrency Error?
WebLogic應用正常運行了幾周后,我突然收到異常:
<Oct 25, 2014 9:31:11 PM EDT> <Error> <HTTP> <BEA-101020>
<[ServletContext@60724164[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
這是異常的來源:
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)
因此,似乎在應用程序運行時的某個時候,WebLogic決定從package b
重新加載類,但是當靜態塊運行時,它發現Properties
對象已被修改。
我不知道它是同時被調用還是被多次調用。 可能是Properties
對象是在應用程序首次重新加載時創建的原始實例,並且CommonStuff
類的重新加載嘗試再次調用putAll()
時。
如果我這樣做會有所幫助:
private static Properties prp = null;
static {
CommonStuff.prp = new Properties();
CommonStuff.load();
}
我不能盲目嘗試,因為它在一家大公司的生產應用程序中。 因此,我試圖了解錯誤原因以及在半夜重新加載類時如何對這些變量進行屬性初始化。
有任何想法嗎?
這可能是WebLogic ClassLoader問題嗎?
在初始化此類之前,類/實例無法訪問某些類的成員。 因此,在靜態構造函數返回之前,沒有人可以訪問新創建的prp
。 將prp
初始值設定項移到static {}
塊上沒有什么區別。 還“老” prp
在“老” CommonStuff
和“新” prp
是不以任何方式連接(因為“老”和“新” CommonStuff
是JVM類不同)。 所有這些使得同時修改prp
可能性看起來很奇怪。
我相信原因在另一個地方。 請注意堆棧跟蹤的第一行: Hashtable
的Enumerator
引發異常。 這是putAll
方法的代碼(與JDK 8一樣,可能多年沒有改變):
for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
put(e.getKey(), e.getValue());
這是引發異常的Enumerator
-它不是prp
,而是參數的Enumerator
。
因此,該異常與prp
而與System.getProperties()
返回的Map
有關。 原因是,遍歷系統屬性映射不是線程安全的。 似乎另一個線程正在同時修改它。
您需要以不同的方式初始化prp
。 我認為clone()
是最簡單的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.