我该如何安全地解决这个Java上下文类加载器问题?

我的数百个用户中只有一个在启动我的Java桌面应用程序时遇到问题。 大约三分之一的时间只有他开始。 其他三分之二的时间在启动时引发NullPointerException:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at java.util.Hashtable.put(Hashtable.java:394)
    at javax.swing.JEditorPane.registerEditorKitForContentType(JEditorPane.java:1327)
    at javax.swing.JEditorPane.registerEditorKitForContentType(JEditorPane.java:1309)
    at javax.swing.JEditorPane.loadDefaultKitsIfNecessary(JEditorPane.java:1387)
    at javax.swing.JEditorPane.getKitTypeRegistry(JEditorPane.java:1344)
    at javax.swing.JEditorPane.getEditorKitClassNameForContentType(JEditorPane.java:1340)
    at javax.swing.JTextPane.<init>(JTextPane.java:76)
    at myapp.Launcher$1.run(Launcher.java:13)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:633)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

我跟踪了堆栈跟踪,发现原因是这样的

Thread.currentThread().getContextClassLoader()

在JEditorPane中返回null。

谷歌搜索显示,这是一个零星的,非常罕见的,神秘的问题,影响到一些人。

我的问题是,我能做些什么来解决问题? 这可能会起作用,如果我在创建EditorPane之前调用它:

Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());

但是我并不是很了解类加载器(我也试图更好地理解它们)。 我觉得改变EDT中的contextClassLoader可能会带来不好的后果。

任何想法我可以做什么?

编辑:我和一些理解Java ClassLoaders的人有了一些通信。 看起来这是一个模糊的ClassLoader竞争条件。 那是Java中的一个错误。


Thread.currentThread().getContextClassLoader()

如果JEditorPane.registerEditorKitForContentType中的代码没有检查上述代码中的空返回值,那么这是JEditorPane一个错误。 请注意, MyClass.class.getClassLoader()也可能返回null。 唯一可以依赖的是系统ClassLoader。

用于为调用设置上下文ClassLoader的模式通常如下所示:

Thread thread = Thread.currentThread();
ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(fooClassLoader);
try {
  // do call that depends on context ClassLoader
} finally {
  thread.setContextClassLoader(old);
}

应该通过setContextClassLoader设置的值将取决于正在使用它的代码的意图和正在运行的ClassLoader框架的设计。

在一个独立的应用程序中,你可能只需要使用这个ClassLoader (将ref传递给当前类):

private ClassLoader findClassLoaderForContext(Class<?> c) {
  ClassLoader context = Thread.currentThread().getContextClassLoader();
  ClassLoader me = c.getClassLoader();
  ClassLoader system = ClassLoader.getSystemClassLoader();
  return (context == null) ? (me == null) ? system : me : context;
}

在ClassLoader敏感的插件框架(Java EE服务器将是一个最好的例子)中,理解加载方案的性质和用法将会付出代价。

链接地址: http://www.djcxy.com/p/43757.html

上一篇: How can I safely solve this Java context classloader problem?

下一篇: Is there a UNIX/pthreads equivalent to Windows manual reset events?