【问题标题】:Spontaneous NullPointerExceptions when firing Events触发事件时自发的 NullPointerExceptions
【发布时间】:2015-06-10 01:10:42
【问题描述】:

我目前正在结合 LWJGL 库制作 JavaFX 关卡编辑器,以实现 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 表达式,显然正如它在错误日志中所说的那样,它也与它们有关。

我不希望有人给我一个确切的答案,我的问题是什么,我做错了什么,因为我没有提供任何代码(因为我的项目太大,我不知道异常在哪里发生)。 不过,我有几个一般性问题:

  1. 这个错误日志是什么意思?

  2. 这可能是什么原因?

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

通过将 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 场景类中

【问题讨论】:

  • @RealSkeptic 这个问题不是“什么是空指针异常”。非常具体。
  • 致任何投票结束此问题的人 - 请不要,除非我们排除它不是 JavaFX 特定的。

标签: java multithreading exception lambda javafx


【解决方案1】:

不是答案,只是解决一个非常相似的问题的建议 - Swing 问题。

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

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

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

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

现在,回到您的特定问题:JavaFX 和 OpenGL 都通过所谓的“线程限制”解决多线程问题。这意味着,一切都是强制单线程的。可能,您的问题源于 javaFx 和 OpenGL 都有各自独立的线程这一事实!我敢打赌,您在 JavaFX 的 EDT 之外进行了一些交互。但是,这只是一个牵强的假设。尝试获取源代码行,我们可以从那里继续。

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

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


更新,

所以,“节点”引用似乎为空(我怀疑“this”是否为空)。 下一步将识别空节点并找到添加它的确切时间。我可能会在所有合理的“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”数组”。

我最好的选择通常是,您从适当的线程外部间接调用调用 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 本身的错误。

【讨论】:

  • 感谢您的回答,我设法通过在 Eclipse 中进入 preferences > java > installed JREs 来显示行号,并将 JRE 从直接安装的 JRE 更改为 JDK 中提供的 JRE。我将编辑帖子以匹配新的起点,
  • 嗯,这很有趣也很好。很高兴知道,我什么时候需要它。
  • 天哪,我也有同样的问题! Scene.dirtyNodes 数组包含大量 null 条目。当我发现罪魁祸首时,我会报告......
  • 我不赞成这个答案,因为它似乎并没有真正得出结论。它只是希望它不是 JavaFX 本身的错误。
【解决方案2】:

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

因为我没有看到你的代码,所以我不确定你到底在哪里做的,但我遇到了同样的问题,结果我已经将一个 GUI 对象传递给了我的一个类,该类在非- 正在更新 GUI 对象的 GUI 线程。所以不要那样做。

【讨论】:

    【解决方案3】:

    如前所述,我们也遇到了这个问题。这似乎是由在 javafx.concurrent.ServiceTaskcall() 方法中更新 UI 引起的,尽管更新是从移交给 Platform.runLater() 的 lambda 执行的。

    因此,我将 UI 更新代码从那里移到了 Service 的 On-Succeeded/Failed-Handlers,它应该放在首位。这似乎为我们解决了这个问题。

    【讨论】:

    • 为提示点赞!我在一个线程中有一个 UDP 侦听器。当它接收到命令时,它会更新 UI(突出显示网格线中的一行)场景中有很多事情发生并且每秒接收到多个命令时它会崩溃。将命令移至 Platform.runLater() 并解决了问题。 12小时试图弄清楚。您的评论点亮了灯泡!谢谢
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-08
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多