Java EDT更改为;系统“;组和线程。currentThread().getContextClassLoader()为空
我突然在我的应用程序中遇到了一个奇怪的问题,但我不确定是否可以隔离这个问题。我无法在SCCEE中重现这个错误,但也许有人可以通过回答下面的两个问题来帮助我理解发生了什么 上下文: 基本上,我有:Java EDT更改为;系统“;组和线程。currentThread().getContextClassLoader()为空,java,multithreading,classloader,Java,Multithreading,Classloader,我突然在我的应用程序中遇到了一个奇怪的问题,但我不确定是否可以隔离这个问题。我无法在SCCEE中重现这个错误,但也许有人可以通过回答下面的两个问题来帮助我理解发生了什么 上下文: 基本上,我有: ... Some treatment ->call to json-io to parse a Json String to Java Objects. see below ... SwingUtilities.inv
...
Some treatment
->call to json-io to parse a Json String to Java Objects. see below
...
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
myUI.start();//starts my user interface
}
});
通常,一切都很顺利。但我在处理中添加了一个调用(一个将Json解析为Java的库,我通常会毫不费力地使用它)
现在,我的另一个图书馆在大喊:
Caused by: java.lang.NullPointerException
at net.sourceforge.jeuclid.elements.support.ClassLoaderSupport.loadClass(ClassLoaderSupport.java:65)
经过一些研究,我发现这是因为Thread.currentThread().getContextClassLoader()
返回null
我转到上面的run()
,发现这两次执行之间的唯一区别是,过去属于组main
的事件调度线程现在属于system
:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
//returns Thread[AWT-EventQueue-0,6,system] instead of Thread[AWT-EventQueue-0,6,main]
myUI.start();//starts my user interface
}
});
最后,我可以用计算机解决这个问题
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
myUI.start();//starts my user interface
}
}
});
问题:
1) 什么样的事情可以让EDT改变团队
2) 编写
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader())的结果是什么代码>?这是个好主意还是个坏主意?如果调用SwingUtilities.invokeLater
是依赖于EDT存在的第一个操作,则该线程将作为副产品创建。因此,创建的线程继承了创建它的线程的线程组,例如
ThreadGroup tg=new ThreadGroup("foo");
new Thread(tg, ()->
SwingUtilities.invokeLater(() -> System.out.println(Thread.currentThread()))
).start();
当作为应用程序的第一个操作执行时,将打印
Thread[AWT-EventQueue-0,6,foo]
正如您可以在上验证的那样
但是请注意,线程组对上下文类加载器没有影响,它只是相同原因的症状。创建线程时,上下文类加载器就像线程组一样被继承,例如
ClassLoader dummyLoader=new URLClassLoader(new URL[0]);
Thread.currentThread().setContextClassLoader(dummyLoader);
SwingUtilities.invokeLater(() ->
System.out.println(Thread.currentThread().getContextClassLoader()==dummyLoader));
将打印true
显然,调用SwingUtilities.invokeLater
,启动EDT创建的线程的上下文加载程序已经是null
(该线程在系统
组中)。将上下文加载器设置为ClassLoader.getSystemClassLoader()
意味着将其设置为默认值,因此它不会产生负面影响,除非您遇到一个环境,其中上下文加载器被故意设置为非默认加载器,尽管null
不能被视为这种情况。换句话说,识别设置为null
的位置并修复它是更好的选择。这里的坏主意是在EDT中运行一个长操作(JSON解析)。它应该只用于快速操作和更改用户界面。但是。。。Json解析在调用SwingUtilities.invokeLater
之前完成。对不起,如果不清楚的话。让我来编辑。必须手动设置类加载器是非常奇怪的。其他地方是否存在“将上下文类加载器设置为null”的(错误)代码?不太可能。与类加载器相关的唯一一行是:Thread.currentThread().getContextClassLoader().loadClass(className)代码>。json io使用它从json实例化Java对象。这正是我想要的答案。谢谢我会调查的。