使用JavaFX Application.stop()方法覆盖Shutdownhook

16

我正在使用shutdownhook进行清理。但由于不能保证shutdownhooks线程总是执行,所以我是否应该将此代码推送到JavaFX应用程序线程(方法stop()),每次关闭应用程序时都会执行?代码运行成本不高。基本上只是在未关闭套接字时关闭套接字并在未杀死进程时杀死进程。

使用Application.stop()清理是否是良好的实践方式,而不是使用ShutdownHook?

来自文档的引用:

当应��程序应停止并提供一个方便的位置来准备应用程序退出和销毁资源时,将调用此方法。 Application类提供的此方法的实现不执行任何操作。

注意:此方法在JavaFX应用程序线程上调用。

这个方法只是用来清理UI资源吗?到目前为止,我没有看到使用shutdownhook而不是stop()的原因。

1个回答

30

stop()只有在通过Platform.exit()退出应用程序时调用(或者如果Platform.implicitExit为true,则在关闭最后一个窗口时)。如果调用System.exit(),或者如果运行JVM的本地进程被中断(例如在*nix-like OS上按下ctrl-C),则会执行关闭挂钩,除了通常的JavaFX应用程序退出方式。

请注意,在调用Application.launch()之前在主线程中注册关闭挂钩似乎很重要。

stop()在FX Application线程上执行,因此可以安全地访问UI元素(例如显示“保存未保存的更改”对话框等)。关闭挂钩在后台线程中运行,因此无法访问UI元素(实际上,FX Toolkit可能已经长时间停止运行)。

因此,选择取决于用例。

为了使这更加具体化,这里是一个快速测试类:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class ShutdownTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        Button platformExit = new Button("Platform Exit");
        platformExit.setOnAction(e -> Platform.exit());
        Button systemExit = new Button("System Exit");
        systemExit.setOnAction(e -> System.exit(0));
        Button hang = new Button("Hang");
        hang.setOnAction(e -> {while(true);});
        HBox root = new HBox(5, platformExit, systemExit, hang);
        root.setPadding(new Insets(20));
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    @Override
    public void stop() {
        System.out.println("Stop");
    }

    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Shutdown hook")));
        launch(args);
    }
}

我在 Mac OS X 上进行了测试。

通过关闭窗口或右键单击 Dock 并选择“退出”来通过“平台退出”按钮退出将执行 stop() 方法和关闭挂钩。

通过“系统退出”按钮、从“活动监视器”中强制退出进程或通过从命令行运行kill id来杀死进程,只会执行关闭挂钩。通过按下“挂起”按钮然后右键单击 Dock 并选择“强制退出”来悬挂应用程序将产生相同的结果。

通过发送 SIGKILL 到进程 (kill -9 idkill -SIGKILL id 命令行) 既不会执行 stop() 方法也不会执行关闭挂钩。


谢谢你的快速回答。通过你的回答,我开始怀疑是否需要使用stop()来关闭一些重要的资源,因为我可以强制终止进程,并且似乎根本没有调用stop(),同样的情况可能也适用于崩溃。 - Tomas Bisciak
4
大多数JavaFX应用程序不会调用System.exit()(您应该始终优先选择Platform.exit()),也不是从命令行运行的(减少了被中断的可能性),因此通常stop()就足够了。但这还取决于您的使用情况。 - James_D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接