一起使用Platform.exit()和System.exit(int)

Pio*_*r G 8 java multithreading javafx

我想关闭一个带有指定返回码的javafx应用程序.浏览SO上的答案,我发现了以下成语:

Platform.exit();
System.exit(0); 
Run Code Online (Sandbox Code Playgroud)

例如: 在关闭我的JavaFX程序
或此处之前停止线程:JavaFX应用程序在关闭后仍然运行

这两个方法一个接一个地执行,看起来我们正在尝试复制某些操作.我认为,如果Platform.exit()成功,它不应该返回到System.exit(0)被调用的地方.但是,如果Platform.exit()仅触发在另一个线程上运行的某些关闭操作,则返回并且System.exit(0)可以调用,这可能会导致某些竞争条件,其中两个线程正在尝试关闭同一个应用程序.

那么,这个成语究竟是如何运作的呢?

Jam*_*s_D 13

调用System.exit(...)终止Java虚拟机.

据我了解,调用Platform.exit()只是表示JavaFX Toolkit关闭,导致在stop()FX Application线程上调用应用程序实例的方法,并允许FX应用程序线程终止.这反过来导致Application.launch()返回.如果你在你的main(...)方法中使用通常的习语:

public static void main(String[] args) {
    Application.launch(args);
}
Run Code Online (Sandbox Code Playgroud)

然后一旦launch()返回,该main()方法没有任何剩余,并且没有(只要没有运行非守护程序线程)应用程序以正常方式退出.在任何情况下Platform.exit()都不会创建调用System.exit(...):但是在某些情况下它会允许JVM退出,因为它没有任何东西可以执行.

如果你调用System.exit(...)JVM基本上会立即退出.因此,例如,如果您main(...)之后的方法中有代码,则Application.launch()该代码在调用之后执行Platform.exit(),而不是在调用之后执行System.exit(...).同样,如果覆盖Application.stop(),则stop()在调用之后调用该方法Platform.exit(),但不会在调用之后调用System.exit(...).

如果您运行非守护程序线程,Platform.exit()则不会强制关闭它们,但System.exit()会.

以下示例应演示此:

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

public class ExitTest extends Application {

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

    @Override
    public void start(Stage primaryStage) {
        Button startThread = new Button("Start non-daemon thread");
        startThread.setOnAction(e -> new Thread(() -> {
            System.out.println("Starting thread");
            try {
                Object lock = new Object();
                synchronized(lock) {
                    lock.wait();
                }
            } catch (InterruptedException exc) {
                System.err.println("Interrupted");
                Thread.currentThread().interrupt();
            } finally {
                System.out.println("Thread complete");
            }
        }).start());

        Button exit = new Button("Simple Exit");
        exit.setOnAction(e -> {
            System.out.println("Calling Platform.exit()");
            Platform.exit();
        });

        Button forceExit = new Button("Force exit");
        forceExit.setOnAction(e -> {
            System.out.println("Calling Platform.exit():");
            Platform.exit();
            System.out.println("Calling System.exit(0):");
            System.exit(0);
        });

        Scene scene = new Scene(new HBox(5, startThread, exit, forceExit));
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
        System.out.println("launch() complete");
    }
}
Run Code Online (Sandbox Code Playgroud)

通常建议您通过调用退出JavaFX应用程序Platform.exit(),这样可以正常关闭:例如,如果您需要任何"清理"代码,则可以将其放入stop()方法中并Platform.exit()允许执行.如果您正在运行必须终止的后台线程,请使它们成为守护程序线程,或者通过执行程序服务执行它们,并从该stop()方法关闭执行程序服务.以下是使用该技术的上述示例的修改.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

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

public class ExitTest extends Application {

    private final ExecutorService exec = Executors.newCachedThreadPool();

    @Override
    public void stop() throws InterruptedException {
        System.out.println("Stop called: try to let background threads complete...");
        exec.shutdown();
        if (exec.awaitTermination(2, TimeUnit.SECONDS)) {
            System.out.println("Background threads exited");
        } else {
            System.out.println("Background threads did not exit, trying to force termination (via interruption)");
            exec.shutdownNow();
        }       
    }

    @Override
    public void start(Stage primaryStage) {
        Button startThread = new Button("Start non-daemon thread");
        startThread.setOnAction(e -> { 
            exec.submit( () -> {
                System.out.println("Starting thread");
                try {
                    // just block indefinitely:
                    Object lock = new Object();
                    synchronized(lock) {
                        lock.wait();
                    }
                } catch (InterruptedException exc) {
                    System.out.println("Interrupted");
                    Thread.currentThread().interrupt();
                } finally {
                    System.out.println("Thread complete");
                }
            });
        });

        Button exit = new Button("Simple Exit");
        exit.setOnAction(e -> {
            System.out.println("Calling Platform.exit()");
            Platform.exit();
        });


        Scene scene = new Scene(new HBox(5, startThread, exit));
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
        System.out.println("launch() complete");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要使用Platform.exit()以便正常关闭,并且想要从中返回值System.exit(...),则以下方法应该有效.请注意,这实际上并不是一种推荐的做法:在生产代码中,您根本不应该依赖支持流程退出代码的平台.

public class App extends Application {

    private static int exitCode = 0 ;

    public static exit(int exitCode) {
        App.exitCode = exitCode ;
        Platform.exit();
    }

    @Override
    public void start(Stage primaryStage) {
        // ...

        someThing.addEventHander(someEventType, e -> App.exit(42));

        // ...
    }

    @Override
    public void stop() {
        // cleanup code...
    }

    public static void main(String[] args) {
        Application.launch(args);
        System.exit(exitCode);
    }
}
Run Code Online (Sandbox Code Playgroud)


ΦXo*_*a ツ 4

在这种情况下,医生是你的朋友:

调用 System.exit(0)将终止 JVM

终止当前正在运行的 Java 虚拟机。该参数用作状态代码;按照惯例,非零状态代码表示异常终止。该方法调用Runtime类中的exit方法。此方法永远不会正常返回。

并且这样做Platform.exit()将终止 FX 应用程序

导致 JavaFX 应用程序终止。如果在调用 Application start 方法之后调用此方法,那么 JavaFX 启动器将调用 Application stop 方法并终止 JavaFX 应用程序线程。然后启动器线程将关闭。如果没有其他非守护线程正在运行,Java VM 将退出。如果从 Preloader 或 Application init 方法调用此方法,则可能不会调用 Application stop 方法。

  • @BoristheSpider `Platform.exit()` 是黑客吗?它允许正常关闭,让 FX 应用程序线程完成,并调用“stop()”回调方法(假设应用程序已“start()”),从而允许清理资源。 (3认同)