Java EDT更改为;系统“;组和线程。currentThread().getContextClassLoader()为空

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

我突然在我的应用程序中遇到了一个奇怪的问题,但我不确定是否可以隔离这个问题。我无法在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解析为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对象。这正是我想要的答案。谢谢我会调查的。