JavaFX 应用程序在 System.exit() 后不会终止

JavaFX application does not terminate after System.exit()

我有一个 JavaFX 应用程序,有时需要 运行 分离进程(更新程序可执行文件)并终止。 我正在 运行 通过使用 ProcessBuilder.command() 设置一个单独的进程,并观察子进程何时会变成 !isAlive(),这意味着进程 运行 完全。在此之后,我试图通过 运行ning Window.getWindows().forEach(::dispose) 然后 System.exit(0).

终止应用程序

调用 System.exit(0) 后应用程序挂起,但如果没有单独的进程 运行 应用程序正确终止。

这是主线程堆栈跟踪的一部分:

"JavaFX Application Thread" #32 prio=5 os_prio=0 tid=0x000000001f4fe000 nid=0x44d0 in Object.wait() [0x0000000023f4d000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Thread.join(Thread.java:1252)

  • locked <0x00000006c21ac608> (a java.lang.Thread) at java.lang.Thread.join(Thread.java:1326) at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106) at java.lang.ApplicationShutdownHooks.run(ApplicationShutdownHooks.java:46) at java.lang.Shutdown.runHooks(Shutdown.java:123) at java.lang.Shutdown.sequence(Shutdown.java:167) at java.lang.Shutdown.exit(Shutdown.java:212)
  • locked <0x00000006c2148fb8> (a java.lang.Class for java.lang.Shutdown) at java.lang.Runtime.exit(Runtime.java:109) at java.lang.System.exit(System.java:971)

所以应用程序似乎在等待 ApplicationShutdownHooks 完成。 应用程序中添加了两个钩子,但删除它们后,stacktrace 保持不变。

可以隐式添加哪些挂钩?也许单独的进程应该运行以不同的方式能够在子进程关闭之前关闭?

UPD:这个应用程序实际上不是一个完整的JavaFX应用程序,而是一个带有JavaFX部分的AWT应用程序。

您的应用程序仍在等待所有关闭挂钩完成,我希望仍然有一些挂钩。

runHooks 方法在应用程序退出时自动 运行。并且应用程序将在完成时退出(除此之外它还会进行一些其他清理)。请看下面的代码:

static void runHooks() {
    Collection<Thread> threads;
    synchronized(ApplicationShutdownHooks.class) {
        threads = hooks.keySet();
        hooks = null;
    }

    for (Thread hook : threads) {
        hook.start();
    }
    for (Thread hook : threads) {
        try {
            hook.join();
        } catch (InterruptedException x) { }
    }
}

每个hook都是一个Thread还没有启动的。关闭会启动所有线程 (hook.start()),然后等待它们全部到 complete/die (hook.join())。

您的堆栈跟踪显示有一个未完成的 shutdownhook 线程。这是找出哪个的方法。

Thread.join() 方法在 this 上同步,'locked' 行告诉您哪个线程对象有问题:

    at java.lang.Thread.join(Thread.java:1252)
    - locked <0x00000006c21ac608> (a java.lang.Thread)
    at java.lang.Thread.join(Thread.java:1326)

这个数字是对象的唯一数字(我认为是虚拟内存地址)。这个数字应该在应用程序的完整线程转储中,或者如果没有,您可以使用调试器在具有所有关闭挂钩 (java.lang.ApplicationShutdownHooks#hooks) 的集合中查找该对象。

在此之后您可以查看此线程以了解它在等待什么。

请注意,您使用的某些库可能会添加 shutdownhook,而不仅仅是您自己的挂钩。

问题出在应用程序结构中。 它实际上是一个带有手动启动的 JavaFX 组件的 Swing/AWT 应用程序。因此,当 Platform.exit()Systen.exit(0) 被调用时,AWT windows 保持活动状态并阻止应用程序完全终止。 在这种情况下,需要正确处理活动 AWT window 然后调用 Platform.exit():

 window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 window.dispose();
 Platform.exit()

然后调用 Platform.exit() 关闭应用程序的 JavaFX 部分。