我的应用程序突然出现了一个奇怪的问题,但我不确定是否可以隔离这个问题。我无法在SCCEE中重现这个错误,但也许有人可以通过回答下面的两个问题来帮助我理解会发生什么。
上下文:
我有,基本上这个:
...
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 IO的调用(一个将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());
会产生什么后果?是好还是坏?
答案 0 :(得分:1)
If your invocation of SwingUtilities.invokeLater
is the first action that relies on the presence of the EDT, that thread will be created as a byproduct. So the created thread inherits the thread group of the thread which created it, e.g.
ThreadGroup tg=new ThreadGroup("foo");
new Thread(tg, ()->
SwingUtilities.invokeLater(() -> System.out.println(Thread.currentThread()))
).start();
when performed as first action of an application, will print
Thread[AWT-EventQueue-0,6,foo]
as you can verify on Ideone.
But note that the thread group has no impact on the context class loader, it’s rather a symptom of the same cause. The context class loader is just inherited exactly like the thread group when the thread is created, e.g.
ClassLoader dummyLoader=new URLClassLoader(new URL[0]);
Thread.currentThread().setContextClassLoader(dummyLoader);
SwingUtilities.invokeLater(() ->
System.out.println(Thread.currentThread().getContextClassLoader()==dummyLoader));
will print true
; (verify on Ideone).
So apparently, the context loader of the thread which invokes SwingUtilities.invokeLater
, initiating the EDT creation, is already null
(and that thread is in the system
group). Setting the context loader to ClassLoader.getSystemClassLoader()
means setting it to its default, so it has no negative impact unless you encounter an environment where the context loader is intentionally set to a non-default loader, though null
can not be considered to be such a case. In other words, identifying the place, where it is set to null
and fixing that, is the better choice.