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

I would like to close a javafx application with a specified return code. Browsing through answers on SO, I found the following idiom:
Platform.exit();
System.exit(0);
for example here:
Stop threads before close my JavaFX program
or here: JavaFX application still running after close
These two methods executed one after another look like we are attempting to duplicate some actions. I would assume, that if Platform.exit() is successful, it should not return to the place where System.exit(0) is called. If however Platform.exit() only triggers some closing action running on another thread, returns and System.exit(0) can be called then this may cause some race condition, where two threads are trying to close the same application.
So, how does this idiom exactly work?

Calling System.exit(...) terminates the Java Virtual Machine.
As I understand it, calling Platform.exit() just signals the JavaFX Toolkit to shut down, resulting in the application instance's stop() method being called on the FX Application thread, and the FX Application Thread being allowed to terminate. This in turn causes Application.launch() to return. If you are using the usual idiom in your main(...) method:
public static void main(String[] args) {
Application.launch(args);
}
then once launch() returns, there is nothing left for the main() method to do, and no (as long as no non-daemon threads are running) the application exits in a normal way. Platform.exit() does not create a call to System.exit(...) under any circumstances: however under certain circumstances it will allow the JVM to exit simply because there is nothing left for it to do.
If you call System.exit(...) the JVM basically exits immediately. So, for example, if you have code in the main(...) method after Application.launch(), that code gets executed after a call to Platform.exit(), but not after a call to System.exit(...). Similarly, if you override Application.stop(), the stop() method is called after a call to Platform.exit(), but not after a call to System.exit(...).
If you have non-daemon threads running, Platform.exit() will not forcibly shut them down, 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's generally recommended that you exit a JavaFX Application with a call to Platform.exit(), which allows for a graceful shutdown: for example if there is any "cleanup" code you need, you can put it in the stop() method and Platform.exit() will allow it to be executed. If you are running background threads which must be terminated, either make them daemon threads, or execute them via an executor service, and shut down the executor service from the stop() method. Here is a modification to the above example which uses this technique.
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() in order to have a graceful shutdown, and you want to return a value from System.exit(...), the following approach should work. Note that this is not really a recommended practice anyway: in production code you should not really rely on the platform supporting a process exit code at all.
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);
}
}

well the Doc is your friend in such a case:
calling System.exit(0) will terminate the JVM
Terminates the currently running Java Virtual Machine. The argument
serves as a status code; by convention, a nonzero status code
indicates abnormal termination. This method calls the exit method in
class Runtime. This method never returns normally.
and doing Platform.exit() will terminates the FX application
Causes the JavaFX application to terminate. If this method is called
after the Application start method is called, then the JavaFX launcher
will call the Application stop method and terminate the JavaFX
application thread. The launcher thread will then shutdown. If there
are no other non-daemon threads that are running, the Java VM will
exit. If this method is called from the Preloader or the Application
init method, then the Application stop method may not be called.

Another approach, that avoids hacks, would be to check if any stages are open and close them using Stage.close(), and then call Platform.exit(). For example, in a two window app:
if (secondWindow != null) secondWindow.close();
Platform.exit();

Related

Updating message in task hangs the application

I am using a background Thread to run my loading code and wish to bind the MessageProperty of the Task to a label.
However, when calling updateMessage() the task hangs; the message is never updated and the next line of code does not execute.
This is using JDK 1.10.1. Here is an MCVE:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
VBox root = new VBox(10);
Label label = new Label("Message");
root.getChildren().add(label);
primaryStage.setScene(new Scene(root));
Task loadingTask = new LoadingTask();
Thread loadingThread = new Thread(loadingTask);
loadingThread.setDaemon(true);
label.textProperty().bind(loadingTask.messageProperty());
loadingThread.start();
primaryStage.setWidth(200);
primaryStage.setHeight(200);
primaryStage.show();
}
}
class LoadingTask<Void> extends Task {
#Override
protected Object call() throws Exception {
System.out.println("Loading task ...");
updateMessage("Loading task ...");
System.out.println("Message: " + getMessage());
return null;
}
}
The output:
Loading task ...
The second System.out.println() is never executed.
Edit:
I added a simple GUI to my MCVE with a label bound to the MessageProperty. The label does get updated to show "Loading task ..." but the console output remains the same; code after the updateMessage() method is called does not execute.
2nd Edit:
I ran my step debugger, and an IllegalStateException is being thrown from the Task class: "Task must only be used from the FX Application Thread"
I'm not sure what that means as the whole point is to run this task on a different thread...
Your only issue is, that you must not access getMessage() from another thread than the FX UI-Thread. Try Platform.runLater(() -> System.out.println("Message: " + getMessage()));

Can multiple showMessageDialogs break swing?

This is simplified code, which would be called from pressing a button in my main JFrame class. Using this code, and then dismissing one of the resulting dialogs, causes all of my active windows in my Java session to either lock up or just go away.
//Broken code
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
List<JFrame> frameList = new ArrayList<>();
frameList.add(new TestJFrame());
frameList.add(new TestJFrame());
frameList.forEach(frame -> frame.setVisible(true));
frameList.forEach(frame -> {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(frame, "Msg", "Title", 0);
frame.setVisible(false);
frame.dispose();
});
});
}
However, if I were to remove the SwingUtilities.invokeLater() section then it works like I would expect (dialog pops up, close the dialog, window goes away, repeat).
//Working code
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
List<JFrame> frameList = new ArrayList<>();
frameList.add(new TestJFrame());
frameList.add(new TestJFrame());
frameList.forEach(frame -> frame.setVisible(true));
frameList.forEach(frame -> {
//SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(frame, "Msg", "Title", 0);
frame.setVisible(false);
frame.dispose();
//});
});
}
I'd rather not use the second one because the actual code is being started in a background thread that is notifying a set of listeners, so if I were to use the second one then it would block up the thread and slow down listeners until the user responds (when I could be processing during that time). What about the invokeLater() is breaking me? Is this expected behavior?
NOTE: This is simplified code pulled out of how I'm actually using it, but the core issue still exists (I have multiple JFrames, and if multiple JOptionPane.showMessageDialog()s were put on invokeLater()s for different JFrames then it breaks me. I tested the above code with a new, isolated, JFrame class created in Netbeans and was able to reproduce the error.
EDIT: I can't seem to reproduce the error in Windows, only seems to happen in Linux.
It is most likely invokeLater() which is breaking your code. If you want to thread this action try using a simple thread or
EventQueue.invokeLater(new Runnable()
{
public void run()
{ //Your joptionpane here
}
});`
Instead of invoke later i prefer using a
1) simple thread
2) TimerTask
3) ScheduledExecutorService
Use one of these methods.
This is an example for using timer task
import java.util.Timer;
import java.util.TimerTask;
public class Task2 {
public static void main(String[] args) {
TimerTask task = new TimerTask() {
#Override
public void run() {
// task to run goes here
System.out.println("Hello !!!");
}
};
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 1 * 1000;
// schedules the task to be run in an interval
timer.scheduleAtFixedRate(task, delay,
intevalPeriod);
} // end of main
}
If you are not satisfied you can use invoke later.
But remember never use invoke and wait its a bad idea
Here is my approach, as I understand the problem is on the locked windows, which are waiting for an event to finish, in swing the events are related with the AWT-EventQueue.
Here is a little explanation about: https://stackoverflow.com/a/22534931/1670134
So, in order to get your window working I used the Future type:
From the java doc:
A Future represents the result of an asynchronous computation. Methods
are provided to check if the computation is complete, to wait for its
completion, and to retrieve the result of the computation. The result
can only be retrieved using method get when the computation has
completed, blocking if necessary until it is ready.
package com.stackoverflow.future;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import com.stackoverflow.frame.MyFrame;
public class MySwingWorker extends SwingWorker<Void, Void>{
#Override
protected Void doInBackground() throws Exception {
final ExecutorService service = Executors.newFixedThreadPool(1);
List<Future<JFrame>> frameList = new ArrayList<Future<JFrame>>();
frameList.add(service.submit(new SwingLoader(new MyFrame())));
frameList.add(service.submit(new SwingLoader(new MyFrame())));
try {
service.shutdown();
service.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
service.shutdownNow();
}
return null;
}
public static void main(String[] args) {
MySwingWorker mySwingWorker = new MySwingWorker();
SwingUtilities.invokeLater(mySwingWorker);
}
}
The loader:
package com.stackoverflow.future;
import java.util.concurrent.Callable;
import javax.swing.JFrame;
public class SwingLoader implements Callable<JFrame>{
private JFrame frame;
public SwingLoader(JFrame frame){
this.frame = frame;
}
#Override
public JFrame call() throws Exception {
frame.setVisible(true);
return frame;
}
}
NOTE: This code is just a proto, in order to provide you with ideas and it must be modified and cleaned in order to achieve the desired results.
Here you are a link with a couple of explanations of each type:
http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/

JavaFX software design

In a JavaFX application, javafx.application.Application must be subclassed, and the inherited launch() method, although it's public, must be called from within this derived class, otherwise an exception is thrown. The launch() method then uses reflection to instantiate the derived class, making it difficult to set values for the class members without losing them when launching. All that appears totally unusual to me, and I was wondering why starting a JavaFX application is so complicated, if that kind of software design (design pattern?) has a name, or if it's just bad design?
EDIT:
To be more specific, I want to use the observer pattern, so my java application gets notified when a document was loaded, like this:
public class MyDocumentLoader extends Application
{
private ChangeListener<Worker.State> changeListener;
public void setChangeListener(ChangeListener<Worker.State> changeListener)
{
this.changeListener = changeListener;
}
...
public void loadDocument(String url)
{
webEngine.getLoadWorker().stateProperty().addListener(changeListener);
webEngine.load(url);
}
...
}
I need the callback member in several methods, and ideally I can have more than one instances of the class that loads documents, so I can set different ChangeListeners for different URLs.
My guess is that this design was motivated by the (vast) number of Swing applications that were incorrectly written, with the "primary" JFrames being instantiated and shown on the wrong thread (i.e. not on the AWT event dispatch thread). My guess is that so many Swing applications were incorrectly written that they had to defensively code the framework against the incorrect usage, and that they wanted to avoid this scenario with JavaFX.
Forcing (well, almost forcing, there are hack-arounds) an FX Application to start this way makes it much harder to write an application incorrectly in a similar way. The launch method (and the equivalent Oracle JVM startup process if you have an Application subclass without a main method and a call to launch) does quite a bit of boilerplate work: it starts the FX toolkit, instantiates the Application subclass and calls its init() method, then on the FX Application Thread it instantiates the primary Stage and passes it to the Application subclass's start(...) method. This then ensures everything is running on the correct thread.
You should basically consider the start(...) method in a JavaFX application as the replacement for the main(...) method in a "traditional" Java application, with the understanding it is invoked on the FX Application Thread.
My recommendation is that the Application subclass should be as minimal as possible; it should just delegate to something else to actually create the UI, and then should just place it in the primary stage and show it. Include a main method that does nothing other than call launch(...) as a fallback for non-JavaFX-aware JVMs. You should only have one instance of one Application subclass present in any JVM. This way your Application subclass has no class members to set, and so the issues you describe simply don't arise.
If you use FXML, this is actually fairly natural: the start(...) method essentially just delegates to the FXML-controller pair to do the real work. If you don't use FXML, create a separate class to do the actual layout, etc, and delegate to it. See this related question which gets at the same kind of idea.
Note also that your statement
the inherited launch() method, although it's public, must be called
from within this derived class
is not entirely accurate, as there is an overloaded form of the launch(...) method in which you can specify the application subclass. So, if you really need, you can just create a stub for starting the FX toolkit:
public class FXStarter extends Application {
#Override
public void start(Stage primaryStage) {
// no-op
}
}
Now you can do:
public class MyRegularApplication {
public static void main(String[] args) {
// start FX toolkit:
new Thread(() -> Application.launch(FXStarter.class)).start();
// other stuff here...
}
}
Note that launch does not return until the FX toolkit shuts down, so it is imperative to put this call in another thread. This potentially creates race conditions, where you may try to do something needing the FX toolkit before launch(...) has actually initialized it, so you should probably guard against that:
public class FXStarter extends Application {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void awaitFXToolkit() throws InterruptedException {
latch.await();
}
#Override
public void init() {
latch.countDown();
}
#Override
public void start(Stage primaryStage) {
// no-op
}
}
and then
public class MyRegularApplication {
public static void main(String[] args) throws InterruptedException {
// start FX toolkit:
new Thread(() -> Application.launch(FXStarter.class)).start();
FXStarter.awaitFXToolkit();
// other stuff here...
}
}
SSCCE (I just used inner classes for everything so this is convenient to run, but in real life these would be standalone classes):
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class BackgroundProcessDrivenApp {
public static void main(String[] args) throws InterruptedException {
Platform.setImplicitExit(false);
new Thread(() -> Application.launch(FXStarter.class)).start();
FXStarter.awaitFXToolkit();
new MockProcessor().doStuff() ;
}
public static class FXStarter extends Application {
private static final CountDownLatch latch = new CountDownLatch(1);
#Override
public void init() {
latch.countDown();
}
public static void awaitFXToolkit() throws InterruptedException {
latch.await();
}
#Override
public void start(Stage primaryStage) { }
}
public static class MockProcessor {
private final int numEvents = 10 ;
public void doStuff() {
Random rng = new Random();
try {
for (int event = 1 ; event <= numEvents; event++) {
// just sleep to mimic waiting for background service...
Thread.sleep(rng.nextInt(5000) + 5000);
String message = "Event " + event + " occurred" ;
Platform.runLater(() -> new Messager(message).showMessageInNewWindow());
}
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
} finally {
Platform.setImplicitExit(true);
}
}
}
public static class Messager {
private final String message ;
public Messager(String message) {
this.message = message ;
}
public void showMessageInNewWindow() {
Stage stage = new Stage();
Label label = new Label(message);
Button button = new Button("OK");
button.setOnAction(e -> stage.hide());
VBox root = new VBox(10, label, button);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 350, 120);
stage.setScene(scene);
stage.setAlwaysOnTop(true);
stage.show();
}
}
}
JavaFX supports a great number of deployment and packaging strategies, ref. https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/toc.html, and having a standardized lifecycle entry- and exit-point simplifies supporting all these strategies.
If you are struggling to initialize your main application class, due to it being instanciated by the JavaFX launcher, your best option is to use the Application.init() and Application.stop() methods, as James_D points out.

Terminate Java Thread on Key

I am writing a java swing program that involves using a thread to update the UI,
The run function in the thread contains a while loop and a sleep timer,
I want to either terminate the while loop or the thread itself when the user presses for example ctrl+c. The thread includes a sleep command, I don't want the user to have to hold down ctrl+c to terminate, I just want to be able to use those keys once.
How is this possible?
public static void main(String[] args) {
.......//Code to set up window
Thread thread = new Thread(){
#Override
public void run() {
while(user has not terminated the program with ctrl+c){
//Do Something
try{
Thread.sleep(5000);
}catch(InterruptedException e){
}
}
}
};
.......//Code to start thread
}
In Java, threads are terminated cooperatively. This means that it requires modifying both the code inside the thread as well as the code outside the thread. Outside the thread, you can signal that the thread should prepare to shutdown by using the Thread.interrupt() method. Inside the thread, you should check Thread.interrupted() to test for interruption (and break from the loop if that is the case). You should also modify your exception handler; the interrupted exception is thrown when Thread.interrupt() was called while the thread was sleeping, so you should modify the content of that handler to break from the loop.
try something like this
class A{
Thread r1Thread;
public static boolean isCtrlCPressed = false;
public static void main(String[] args) {
.......//Code to set up window
MyRun r1 = new MyRun();
r1Thread = new Thread(r1);
r1Thread.start();
}
public void someMethodThatDetectCtrlC(){
r1Thread.interrupt();
}
}
Your Thread
class MyRun implements Runnable{
#Override
public void run() {
// TODO Auto-generated method stub
try{
Thread.sleep(5000);
}catch(InterruptedException e){
}
}
}
Make a boolean called "running"
Change your while loop to while(running)
Add a keylistener, make it listen for Ctrl + C.
If it hears Ctrl + C, set running = false.
Since running == false, the while loop will then stop.

JavaFX application still running after close

I'm having problem to close my javaFX application, when I click the close button from my stage, my application disappears but if I look for it in my task manager my application still there without close.
I've tried to use this code below to force it close the main thread and all childrens threads but the problem persists.
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
}
});
Does your application spawn any child threads? If so have you ensured that you terminate them (assuming that they're not daemon threads)?
If your application spawns non-daemon threads then they (and therefore your app) will continue to live on until such time you kill the process
The only way was to call System.exit(0);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
System.exit(0);
}
});
[EDITED]
System.exit will just hide your application, if you open SO's manager task your application will be there. The correct way is to check your Threads, one by one and close all before close application.
First Look Here
public void start(Stage stage) {
Platform.setImplicitExit(true);
stage.setOnCloseRequest((ae) -> {
Platform.exit();
System.exit(0);
});
}
I currently had this problem while using an ThreadExecutor in the controller.
Application does not exit if the ThreadExecutor is not shutdown.
See here:
how-to-shut-down-all-executors-when-quitting-an-application
As it can be a problem to recognize an application exit in the controller, you can get a reference to the controller from your Application class like so (using the sample application from Eclipse):
public class Main extends Application {
private SampleController controller;
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
BorderPane root = (BorderPane)loader.load(getClass().getResource("Sample.fxml").openStream());
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
controller = loader.<SampleController>getController();
}
catch(Exception e)
{
e.printStackTrace();
}
}
Your Application overrides the stop method, where you can call a housekeeping method of the controller (i use a method called startHousekeeping):
/**
* This method is called when the application should stop,
* and provides a convenient place to prepare for application exit and destroy resources.
*/
#Override
public void stop() throws Exception
{
super.stop();
if(controller != null)
{
controller.startHousekeeping();
}
Platform.exit();
System.exit(0);
}
I was able to fix this problem by calling com.sun.javafx.application.tkExit(). You can read more in my other answer here: https://stackoverflow.com/a/22997736/1768232 (these two questions really are duplicates).
Just a note:
Try checking if you use
Platform.setImplicitExit(false);
Had a similar problem and overflowing my tasks. The above line will not make the stage close, it will hide it.
To imitate pressing 'x' one can do:
stage.fireEvent(new WindowEvent(stage, WindowEvent.WINDOW_CLOSE_REQUEST))

Categories