触发事件时自发的NullPointerExceptions

时间:2015-04-05 13:16:02

标签: java multithreading exception lambda javafx

我目前正在与LWJGL库结合使用JavaFX Level Editor,以实现OpenGL功能,从而使用多线程。

我的问题是,有时当我解雇JavaFX事件时(当我按下按钮/键等时),我得到了这个自发的java.lang.NullPointerException。我似乎无法弄清楚错误何时发生的模式,并且由于一些奇怪的原因,堆栈跟踪不能为我提供异常发生的位置。我所知道的是,当我以某种方式与JavaFX应用程序线程交互时,就会发生这种情况。

但是当它确实发生时,它不仅会将其打印到控制台一次然后崩溃。发生的情况是应用程序不断地反复打印出错误消息,直到我强行关闭应用程序。发生错误时,我似乎无法再触发某些特定事件。

这是我得到的自发重复错误消息:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Unknown Source)
at javafx.scene.Scene$ScenePulseListener.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Unknown Source)
at com.sun.javafx.tk.Toolkit$$Lambda$153/452428720.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.firePulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/424424770.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/12064136.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

我想这与"同步节点"有关。由于我使用多线程来运行OpenGL渲染循环,这可能与案例有关。我也在使用Java8中的Lambda Expression,显然正如它在错误日志中所说的那样,它也与它们有关。

我不希望有人给我一个确切的答案,我的问题是什么,以及我做错了什么,因为我没有提供任何代码(因为我的项目太大而且我不知道在哪里发生例外)。 但是,我有一些通用的问题:

  1. 此错误日志的含义是什么?

  2. 可能导致这种情况的原因是什么?

  3. 为什么它没有向我提供有关异常发生地点的任何信息?

  4. 我设法通过将Eclipse中的JRE从JRE安装切换到JDK提供的jar来从堆栈跟踪中获取行号。这允许我从编译的API中获取行号,例如JavaFX本身。

    这是新的错误日志:

    Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2289)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2419)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
    at com.sun.javafx.tk.Toolkit$$Lambda$153/478814140.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
    at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/1940618951.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
    at com.sun.glass.ui.win.WinApplication$$Lambda$38/640174177.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
    

    我的错误在于JavaFX类,可能在我的lambda表达式中的某个地方,因为它仍然说的唯一地方(未知来源)也是" lambda"。也许堆栈跟踪不能在lambdas中显示行号?

    无论如何,这是返回NullPointerException的代码行:

    if (node.getScene() == Scene.this)
    

    这是在JavaFX Scene类

4 个答案:

答案 0 :(得分:2)

不是答案,只是对一个非常类似的问题进行故障排除的建议 - 一个Swing one。

为了避免任何猜测,我们应该查看源代码 - 解决“未知来源”部分。 您提供的堆栈跟踪缺少行号。 这是因为,编译标准JRE时没有任何调试信息。 有一次,我相信在Sun时代,可以下载一个针对开发人员的单独发行版,其中包含所有调试符号。 除了具有确切的行号之外,这还允许在JDK代码内设置断点。

我们可以从那里开始调查问题。

如果没有带有调试符号的JRE,您可以随时尝试编译自己的! 我曾经成功编译了伴随JDK发行版的“src.zip”文件。虽然它不是自包含的!有几个部分缺失,一些特定于Linux的类等。来自JDK的javac本身存在文件问题 - 它一直耗尽内存。幸运的是,Eclipse的javac编译器可以处理大代码库并部分编译类。

然后,我在引导类路径中使用生成的jar(使用调试符号编译的src.zip)运行我的程序。通常,您不能修改“java。”和“sun。”包中的任何内容。使用bootstrap类路径,您可以。

现在,回到您的某个问题:JavaFX和OpenGL都通过所谓的“线程限制”来解决多线程问题。这意味着,一切都是强有力的单线程。也许,你的问题源于这样一个事实:javaFx和OpenGL都有它们各自的线程!我敢打赌,你在JavaFX的EDT之外做了一些互动。但是,这只是一个遥不可及的假设。尝试获取源代码行,我们可以从那里继续。

当我需要调试信息时,我正在按照这里的答案:debug jdk source can't watch variable what it is

但是,可能不需要所有的工作!我刚刚了解到,您可以将源文件本身附加到引导类路径,如下所示:https://stackoverflow.com/a/10498425


更新

所以,似乎“节点”引用为空(我怀疑“this”为null)。 下一步将识别空节点并找到添加它的确切时间。我可能会在所有合理的“addNode”调用中添加一些断点(或打印输出语句) - 来自您的程序。

从源代码(我快速浏览http://grepcode.com/file/repo1.maven.org/maven2/net.java.openjfx.backport/openjfx-78-backport/1.8.0-ea-b96.1/javafx/scene/Scene.java#2263)看来,“null”引用来自“dirtyNodes”数组“。

我最好的选择是,您正在间接调用从正确的Thread外部调用addToDirtyNodes(http://grepcode.com/file/repo1.maven.org/maven2/net.java.openjfx.backport/openjfx-78-backport/1.8.0-ea-b96.1/javafx/scene/Scene.java#503)。令我惊讶的是,第一行检查是否从正确的那个调用它:

Toolkit.getToolkit()checkFxUserThread();

您是否碰巧在程序的输出中看到“Not on FX application thread; currentThread =”这一行?

我们只是希望,这不是JavaFX本身的错误。

答案 1 :(得分:2)

不要在非GUI线程上修改您的GUI。

由于我没有看到你的代码,我不知道你到底在做什么,但我遇到了同样的问题,结果发现我已经将一个GUI对象传递给我的一个类正在更新GUI对象的非GUI线程上的方法。所以不要这样做。

答案 2 :(得分:0)

如上所述,我们也有这个问题。它似乎是由javafx.concurrent.Service Task的{​​{1}} call()方法更新用户界面引起的,尽管更新是从lambda移交给Platform.runLater()执行的

所以我将UI更新代码从那里移到了Service的On-Succeeded / Failed-Handlers,它本应该放在第一位。这似乎已经为我们消除了这个问题。

答案 3 :(得分:0)

有两个与此相关的JDK Bug条目:

8u20之前的任何JDK版本都可能受此问题的影响。