Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javafx: Difference between javafx.concurent and Platform.runLater?

I'm curious as to what exactly the difference is between javafx.concurent and Platform.runLater for multithreaded JavaFx programming.

Does it mean that with javafx.concurrent, we can have multiple actual drawing threads or does it all end up on one thread anyway?

E.g One thing I enjoyed was using JavafX and swing concurrently as they both used 2 different drawing threads. I would use swing for the heavy stuff (e.g. opening a FileChooser) and use JavaFX for the core visual stuff e.g playing a seamless, looping video. However, the mac makes this impossible because of that headless exception error so everything fell on javafx and that meant a lot of pauses when doing things like opening filechoosers.

If I rewrite my app With javafx.concurrent, could I essentially mimic that 2 draw thread experience as I once did with Swing + JavaFX?

like image 323
Glstunna Avatar asked Dec 09 '22 13:12

Glstunna


1 Answers

Platform.runLater

A Worker is complementary to Platform.runLater.

  • Use Platform.runLater when you are executing off of the JavaFX Application Thread and you want to run some logic on the JavaFX application Thread.
  • Use a Worker when you are running on the JavaFX Application Thread and want to spawn some logic or (especially) I/O on a new thread so that you don't block the JavaFX Application Thread.

You would never want to do network I/O inside a Platform.runLater's run method, but would often want to do it in a Worker's call method.

Task and Service

Consider using the Task or Service subclasses of Worker. These are JavaFX wrappers for FutureTask (which is in turn a Runnable). Workers provide a call method to run logic on a background thread. They maintain execution status (with thread safe callback notification to the JavaFX thread for state changes) and return results of the call via value, message and exception properties.

Take advantage of the design patterns in the Task and Service javadoc examples to simplify creation of thread-safe applications with features such as:

  • Asynchronous fetching of data for UI update.
  • Periodic message updates for task progress.
  • Constructing Node graphs which are not yet attached to a displayed scene.
  • Monitoring progress via progress bars, etc.

Using Workers and Platform.runLater together

Also, usage of Task and Service is not incompatible with use of Platform.runLater. For instance, if you have a very long running Task from which you want to return partial results to the UI periodically or as a buffer fills, then executing Platform.runLater in the task's call method is the way to do that.

Working with existing threading systems

Workers are useful when you don't have an existing threaded service provided by a library, but are instead creating your own threads to execute in the background. If you have an existing threaded service, then you will need to use Platform.runLater to perform logic on the JavaFX application thread.

Be careful writing multi-threaded code

Note that you still need to know what you are doing, even if you use a Worker. You must still take care that you don't violate standard JavaFX concurrency rules, such as never updating Nodes on the active scene graph (including not updating values that Nodes in the active scene graph are bound to - such as the observable list of items backing a ListView).

Answering some of your addition questions

Does it mean that with javafx.concurrent, we can have multiple actual drawing threads or does it all end up on one thread anyway?

There is only one render thread in JavaFX. You cannot make more render threads using JavaFX concurrent. You can do things like create nodes off the JavaFX thread or set pixels to an off screen WriteableImage or Canvas using many threads, but eventually every render operation passes through a single thread managed by the JavaFX system over which you have no control.

If I rewrite my app With javafx.concurrent, could I essentially mimic that 2 draw thread experience as I once did with Swing + JavaFX?

No. Even if you could, I don't think it would be advisable. With such a model it is far too easy to create subtle, hard to debug thread processing related errors. And the gain you might see from such a setup may be less than you may wish for or expect.

See related articles on why having 2 or more "draw threads" is likely inadvisable:

  • Threadaches
  • Multithreaded Toolkits: A failed dream

Java 8 is adding an experimental command line switch to use the same thread for the JavaFX application thread and the Swing event dispatch thread. The main reason for this is that it simplifies the programming model.

everything fell on javafx and that meant a lot of pauses when doing things like opening filechoosers.

Perhaps there were inefficiencies in your code (such as performing I/O on the UI thread) which caused the pauses.

the heavy stuff (e.g. opening a FileChooser)

Opening and rendering a FileChooser is not heavy. JavaFX can easily handle such an operation without a performance degradation. What can be time consuming is stuff related to I/O, for example walking a large file tree recursively to get file attributes. What you can do in such cases is spawn a thread for the I/O run it in a Worker and periodically feed back partial results to the UI thread via Platform.runLater. Such a scheme will work well. The bottleneck is not the drawing, so having another drawing thread provides no advantage. The bottleneck is the slow I/O system and this bottleneck is mitagated by the using a separate thread for I/O so that the main UI thread is not impacted and the user does not experience UI freezes while I/O is occurring.

like image 126
jewelsea Avatar answered May 06 '23 17:05

jewelsea