Usage of JavaFX Platform.runLater and access to UI from a different thread
Asked Answered
S

2

10

I have a few questions about Platform.runLater. I have a JavaFX Application class. In this class I run a thread (The thread reads data from a network socket).

Now when I create a new Stage inside the thread, the system throws an execption (JavaFX event dispatcher thread and my netork-read thread are not the same) - I understand this behaviour.

But the other side is, I append the text from the network-reader to an existing TextArea or add/remove some items in a ListView<String> - this doesn't throw an exception - why ? I thought JavaFX is singlethreaded (The ui library part). Is this the same thing as in Swing: Sometimes it works and sometimes you have just garbage (Because EDT)?

My questions:

  • When does the JavaFX event dispatcher thread throw an exception and when not ?
  • Are the any good documents about this
  • Is there an easier (shorter & cleaner) way to use Platform.runLater with a run() method ? In combination with a try catch (or multiple catch), it looks very strange

I know the usage of Platform.runLater in a thread isn't that nice (design solution)

Schneider answered 1/3, 2013 at 14:43 Comment(3)
Or is this the same thing as in Swing: Sometimes it works and sometimes you have just garbage? please what do you talking about, all updates to the Swing GUI must be done on EDT, single threating for GUI is advantage in most cases, appliedd for lots of GUI frameworks in various programming languagesAmory
Yes, I mean EDT in Swing (Just use UI in the EDT context). I mean, that when you access a Swing UI outside EDT, sometimes it works and sometimes notSchneider
Please include in your question a code sample demonstrating In combination with a try catch (or multiple catch), it looks very strange.Madness
F
13

"this doesn't throw an exception - why?" because not all such cases are cought... Possibly, because of performance considerations, possibly, it is just a missed functionality.

All interactions with JavaFX objects (including creation) must be done on JFX thread, if you want to access those JFX objects from another thread - use runLater or runAndWait methods. If it doesn't throw exception now, it possibly will start to throw exceptions in the future. Any interaction with JFX object may cause a subsequent actions and event, which will be cought by some thread checker - you cannot be sure.

I don't think, there is any good documentation on this - just a simple rule - use runLater or runAndWait.

Shorter and cleaner way - will be provided in JDK 8 using Lambda.

Fluecure answered 1/3, 2013 at 15:7 Comment(2)
Ok, thank you. Good to know - I'll use Platform.runLater. Concerning to JDK 8 - sadly I can't wait until September 2013 :(Schneider
You can download its preview. Actually, you can start using JDK 8 on your risk. And it contains lambda, as far as I know. jdk8.java.net/download.htmlFluecure
M
18

Alexander's answer catches the most important points regarding your questions.

This answer provides some supplemental information.

When does the JavaFX event dispatcher thread throw an exception and when not ?

The JavaFX system does not always check that accesses to objects affecting the active scene graph are properly restricted to the JavaFX thread. Ultimately, ensuring such thread safety is the responsibility of the JavaFX application programmer - not the JavaFX system. You must be very careful when performing multi-threaded programming in JavaFX, otherwise application behaviour may fail or become unpredictable.

Are the any good documents about this

Try the the JavaFX tutorial: Concurrency in JavaFX.

Is there an easier (shorter & cleaner) way to use Platform.runLater with a run() method?

No. Platform.runLater is as simple as it gets.


As an aside . . .

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.

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.

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.

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.

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).

Madness answered 2/3, 2013 at 1:0 Comment(3)
Ok, thank you very much for this great explanation - I need some time to read this articles and make some codetestsSchneider
"...including not updating values that Nodes in the active scene graph are bound to - such as the observable list of items backing a ListView". Can you explain this a bit more or provide a link with more details?Pull
It is a worthwhile question, but a full answer is outside the scope of this question. Please create a new question and, if it is well written, I am sure that it will receive at least one or two very good answers. You can provide a link to and quote from this answer in your question. Ask for some code examples to provide a concrete demonstration.Madness
F
13

"this doesn't throw an exception - why?" because not all such cases are cought... Possibly, because of performance considerations, possibly, it is just a missed functionality.

All interactions with JavaFX objects (including creation) must be done on JFX thread, if you want to access those JFX objects from another thread - use runLater or runAndWait methods. If it doesn't throw exception now, it possibly will start to throw exceptions in the future. Any interaction with JFX object may cause a subsequent actions and event, which will be cought by some thread checker - you cannot be sure.

I don't think, there is any good documentation on this - just a simple rule - use runLater or runAndWait.

Shorter and cleaner way - will be provided in JDK 8 using Lambda.

Fluecure answered 1/3, 2013 at 15:7 Comment(2)
Ok, thank you. Good to know - I'll use Platform.runLater. Concerning to JDK 8 - sadly I can't wait until September 2013 :(Schneider
You can download its preview. Actually, you can start using JDK 8 on your risk. And it contains lambda, as far as I know. jdk8.java.net/download.htmlFluecure

© 2022 - 2024 — McMap. All rights reserved.