A call to System.exit(...) terminates the Java virtual machine.
As I understand it, a call to Platform.exit() simply signals the completion of the JavaFX Toolkit, as a result of which the called instance of the stop() application instance is called in the FX application thread, and the FX application thread is allowed to terminate. This, in turn, results in Application.launch() returning. If you use the normal idiom in the main(...) method:
public static void main(String[] args) { Application.launch(args); }
then after launch() returns for the main() method, nothing remains, and no (until the non-daemon threads are executed), the application exits in the usual way. Platform.exit() does not call System.exit(...) under any circumstances: however, under certain circumstances, this will allow the JVM to exit simply because there is nothing left for it.
If you call System.exit(...) , the JVM basically exits immediately. So, for example, if you have code in the main(...) method after Application.launch() , this code runs after calling Platform.exit() , but not after calling System.exit(...) . Similarly, if you override Application.stop() , the stop() method is called after calling Platform.exit() , but not after calling System.exit(...) .
If you have threads without a daemon, Platform.exit() will not force them to close, but System.exit() will.
The following example should demonstrate this:
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"); } }
It is generally recommended that you exit the JavaFX application with a call to Platform.exit() , which allows for an elegant shutdown: for example, if you need some kind of "cleansing" code, you can put it in the stop() method and Platform.exit() will allow fulfill it. If you use background threads that must be completed, either create daemon threads for them, or execute them through the executing service, and terminate the executing service from the stop() method. The following is a modification of the above example that uses this method.
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 {
If you want to use Platform.exit() to have a graceful shutdown and want to return a value from System.exit(...) , the following approach should work. Please note that this is not a true recommended practice: in production code, you should not fully rely on a platform that supports the process exit code.
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) {