Using Platform.exit () and System.exit (int) together

I would like to close the javafx application with the specified return code. Looking through the answers to SO, I found the following idiom:

Platform.exit(); System.exit(0); 

for example here: Stop threads before closing my JavaFX program
or here: JavaFX application still works after closing

These two methods, executed one after the other, look as if we are trying to duplicate some actions. I would suggest that if Platform.exit() successful, it should not return to the place where System.exit(0) called. If, however, Platform.exit() only launches some closing action on another thread, and System.exit(0) can be called, then this can lead to some race condition when two threads try to close the same application.

So how does this idiom work for sure?

+5
source share
2 answers

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 { // 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"); } } 

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) { // ... 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); } } 
+7
source

It's good that Doc is your friend in this case:

calling System.exit(0) will terminate the JVM

Closes a running Java virtual machine. The argument serves as a status code; by convention, a non-zero status code indicates an abnormal termination. This method calls the exit method to the Runtime class. This method never returns normally.

and executing Platform.exit() will terminate the FX application

Causes the JavaFX application to terminate. If this method is called after calling the application start method, JavaFX starts, it calls the application stop method and the JavaFX application thread terminates. Then the startup thread will be completed. If here are no other non-daemons that run, the Java VM will exit. If this method is called from Preloader or Application init, then the application stop method cannot be called.


both in my opinion are bad approaches to destroying the application ...

+2
source

Source: https://habr.com/ru/post/1271531/


All Articles