Swing timer alternative for JavaFX and the thread

2019-06-01 00:50发布

问题:

Is it safe to use Swing timer for JavaFX or there is an special alternative for Swing? What is the differnce of the thread management between JavaFX and Swing?

In fact I'm interested to know the equivalents of Swing Timer, SwingUtilities.invokeLater() and invodeAndWait() for JavaFX.

By the way what if we use some Swing components in the JavaFX? Should we use two parallel Timer/Threads for updating those components?

回答1:

JavaFX equivalent of SwingUtilities.invokeLater()

Platform.runLater(java.lang.Runnable runnable)

See also JavaFx response to SwingUtilities.invokeLater.

JavaFX equivalent of invokeAndWait()

The public JavaFX API deliberately does not expose an invokeAndWait call on Platform.runLater because it is easy to deadlock yourself with it, so you can use the below code instead as long as you know exactly what you are doing.

final FutureTask query = new FutureTask(new Callable() {
    @Override
    public Object call() throws Exception {
        return queryPassword();
    }
});
Platform.runLater(query);
System.out.println(query.get()); // the get blocks until the query FutureTask completes.

See also Return result from javafx platform runlater.

JavaFX equivalent of javax.swing.Timer.

Use a Timeline. The following will update a label displaying the date every second:

DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Label dateLabel = new Label();
Timeline timeline = new Timeline(
    new KeyFrame(
      Duration.ZERO,
      actionEvent -> dateLabel.set(dateFormat.format(new Date()))
    ),
    new KeyFrame(
      Duration.seconds(1)
    )
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();

See also the Timeline based answer to How to update the label box every 2 seconds in java fx?.

If we use some Swing components in the JavaFX? Should we use two parallel Timer/Threads for updating those components?

I think not, depends on the app, but generally a single Timer for the application would be preferred. This is kind of a specialized case. Generally, if you have some asynchronous process happening on a Timer, you want it to happen all at once, so the Timer fires, does some processing, then shunts the results back to the GUI. As you are mixing two UI frameworks, it's a little more complicated because you want to update both frameworks with results at the same time or within the same render frame.

To approximate this, I'd advise using just a plain java.util.Timer, rather than a javax.swing.Timer, or use a ScheduledExectorService if you need more flexibility. Then, in the TimerTask or scheduled Runnable, perform your processing logic and after the processing is done make calls to Platform.runLater and seperately SwingUtilities.invokeLater as appropriate to shunt the results back to either JavaFX or Swing components.

Of course you should consider if mixing two frameworks such as this and dealing with the potential threading complications is worth it. If you are able to just use a single framework and rely on the concurrency approach which works best with that framework, I think that would be a preferred approach.

What is the difference of the thread management between JavaFX and Swing?

From a user point of view it is pretty similar. Both JavaFX and Swing remain single threaded frameworks for application layer UI processing. All user code for JavaFX runs on the JavaFX application thread. Moreover any code which may modify the active scene graph (nodes displayed on the stage), must run on the JavaFX application thread. These rules are similar to the nature of thread management in Swing programming.

The JavaFX application thread and the Swing thread in the initial release of Java 8 are different by default. So:

  1. To update Swing components from the JavaFX application thread, use Platform.runLater to switch processing from the JavaFX thread to the Swing thread.
  2. To update JavaFX nodes from the Swing thread, use SwingUtilities.invokeLater to switch processing from the Swing thread to the JavaFX thread.

A future release of the Java platform may feature a unified application thread for Swing and JavaFX.

Note that the internal threading implementation used in library code differs between Swing and JavaFX. JavaFX will use different hardware and software rendering pipelines which can run on their own thread. However, this internal implementation detail is completely hidden from the application programmer.

Reference Documentation

Concurrency in JavaFX Tutorial by Oracle. In particular, see the sections on Task and Service for managing background operations from JavaFX, topics which are not explicitly discussed in this answer.