Stage.setOnCloseRequest() 和 Runtime.addShutdownHook() 有什么区别?

What are the differences between Stage.setOnCloseRequest() and Runtime.addShutdownHook()?

编写 JavaFX 应用程序时,您可以使用 setOnCloseRequest(EventHandler<WindowEvent>) 方法为任何 javafx.stage.Stage 提供关闭挂钩。如果您使用主要的 JavaFX 场景执行此操作,它会用作应用程序关闭挂钩,并可用于安全地 save/release 重要的系统资源等。但是如果您实现java.lang.Thread 并使用 Runtime.getRuntime().addShutdownHook(Thread) 方法将其添加为关闭钩子。

这些方法之间有什么区别。如果我调用 Platform.exit(),两者都有效吗?如果我调用 System.exit(int),两者都有效吗?哪一个被认为是最安全的(意思是,更好地确保 saving/releasing 系统资源)方法?除了我应该考虑的方法之外,还有更好的方法吗?

这些是根本不同的东西。

当用户请求关闭该特定阶段(通常通过按下 OS-specific "close" window)。它在 FX 应用程序线程上调用,并将在 window 实际关闭之前调用。它的执行并不意味着应用程序正在退出,FX 工具包正在关闭,或者 Java 虚拟机正在退出。这里的处理程序不仅可以假定 FX 工具包仍然是 运行,还可以修改 UI(因为它在 FX 应用程序线程上)并且可以否决关闭 window 的请求通过消费事件。

关闭挂钩是用户提供的线程,在 Java 虚拟机退出时执行。它是自己的线程,并作为关闭序列 的一部分执行。因此,它不能假定任何其他服务是 运行。来自 API docs:

They should also not rely blindly upon services that may have registered their own shutdown hooks and therefore may themselves in the process of shutting down. Attempts to use other thread-based services such as the AWT event-dispatch thread, for example, may lead to deadlocks.

适用于 AWT 事件分派线程的相同警告也适用于 FX 应用程序线程。

在某些非常特殊的情况下,调用 setOnCloseRequested 处理程序可能表明 JVM 可能很快就要退出。这些情况包括以下所有内容,但我可能遗漏了一些内容:

  1. 处理程序不使用事件
  2. 舞台是最后一个开放的舞台
  3. Platform.isImplicitExit() returns 真
  4. 没有非守护线程 运行,none 由 Application 实例的 stop() 方法启动

你应该使用哪个完全取决于你想做什么。如果目标是释放作为 JavaFX 应用程序的一部分启动的资源,这些资源仅在应用程序退出时不再需要,我不会使用其中任何一个,但会覆盖 Application.stop() method.