JDK-8114199 : isFxApplicationThread check fails after last window is closed
  • Type: Bug
  • Component: javafx
  • Sub-Component: application-lifecycle
  • Affected Version: fx2.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2011-08-05
  • Updated: 2015-06-16
  • Resolved: 2011-08-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
fx2.0Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
There is a problem with Toolkit.exit(), and how it clears the fxUserThread field. The problem is that any subsequent call to isFxApplicationThread will return false, since anyThread == null will return false. This can happen quite easily. I have a background thread which does Platform.runLater(). In the body of the runLater(), it checks isFxApplicationThread (because it tries to set some property which performs this check). After closing the window, the background thread and runLater() pump still execute, but the isFxApplicationThread subsequently fails, even though the fx application thread is still processing!


import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

/**
 */
public class TaskSample extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override public void start(Stage primaryStage) throws Exception {
        final Button startButton = new Button("Start");
        startButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent event) {
                startButton.setText("Running");
                new Thread(new Runnable() {
                    @Override public void run() {
                        try {
                            // Do some seriously complicated stuff :-)
                            double aperyConstant = 1;
                            for (int i=2; i<1000000; i++) {
                                aperyConstant += 1.0 / Math.pow(i, 3);
                                final int iteration = i;
                                final double constant = aperyConstant;
                                Platform.runLater(new Runnable() {
                                    @Override public void run() {
                                        if (!Platform.isFxApplicationThread()) {
                                            System.err.println(Thread.currentThread());
                                            System.err.println("isFxApplicationThread returns false");
                                        } else if (iteration % 1000 == 0) {
                                            System.out.println("Constant is " + constant);
                                        }
                                    }
                                });
                                Thread.sleep(1);
                            }
                        } catch (InterruptedException ex) {
                            System.err.println("Interrupted");
                        }
                    }
                }).start();
            }
        });

        Scene scene = new Scene(startButton);
        primaryStage.setScene(scene);
        primaryStage.setVisible(true);
    }
}

Comments
verified in build 44
02-09-2011

With the recent fixes to application stop, and with the workaround described in RT-15601 implemented for Mac, this no longer fails.
23-08-2011

Note that two new issues have been filed relating to this that should be fixed in a presidio update release: RT-16245 and RT-16246
23-08-2011

The original issue is not reproducible on Windows, so lowering to Major (and Mac currently calls System.expit as a workaround for a whole host of exit-related problems, and this workaround means the issue won't happen on Mac either). With our existing app life-cycle API, an app has a natural point at which to know that it shouldn't post more Runnables on the queue, that being when its stop() method is called. The stop method is called specifically to give the application notice that it's time to pack up and go home. So I think we're just left with defining and implementing the behavior of runLater if it is called after the platform has called Toolkit.exit(). We have two possible choices: 1) Silently ignore the call 2) Throw a runtime exception The latter may be slightly preferable, but is a behavioral change that I don't think is worth doing at this point. I propose doing #1, which is what looks like is happening by accident on Windows anyway. I would propose to do it in platform-independent code, so that the behavior will be the same on all platforms. Note that as part of doing this, PlatformImpl.runLater (which isn't exposed publicly), will need to throw an exception in this case, since otherwise it would wait forever.
19-08-2011

And note that such an app can and should override Application.stop() to know when the application is done and no more work will be done on the FX Application thread.
10-08-2011

The root cause of this is that we don't stop processing runLater requests after the toolkit shutdown is done, which we should do for a number of reasons.
10-08-2011

Raising to critical since printing to console stack traces is bad, and a very easy situation to get into when writing apps that are using Task.
05-08-2011