调用System.exit(...) 会终止Java 虚拟机。
据我了解,调用 Platform.exit() 只是指示 JavaFX Toolkit 关闭,导致在 FX 应用程序线程上调用应用程序实例的 stop() 方法,并允许 FX 应用程序线程终止。这反过来又导致Application.launch() 返回。如果您在 main(...) 方法中使用惯用语:
public static void main(String[] args) {
Application.launch(args);
}
然后一旦launch() 返回,main() 方法就没有什么可做的了,并且没有(只要没有非守护线程正在运行)应用程序以正常方式退出。 Platform.exit() 在任何情况下都不会创建对 System.exit(...) 的调用:但是在某些情况下,它会允许 JVM 退出,因为它无事可做。
如果你调用System.exit(...),JVM 基本上会立即退出。因此,例如,如果您在Application.launch() 之后的main(...) 方法中有代码,则该代码将在调用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");
}
}
通常建议您通过调用Platform.exit() 退出JavaFX 应用程序,这样可以正常关闭:例如,如果您需要任何“清理”代码,您可以将其放入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");
}
}
如果你想使用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);
}
}