Reputation: 69279
When using JavaFX 8, we need to run interactions with the GUI via Platform.runLater
, or else they will throw exceptions if ran from another thread.
However the implementation of Platform.runLater
never checks whether it currently is on the JavaFX thread.
I wrote the following method:
public static void runSafe(final Runnable runnable) {
Objects.requireNonNull(runnable, "runnable");
if (Platform.isFxApplicationThread()) {
runnable.run();
}
else {
Platform.runLater(runnable);
}
}
This ensures that it can never be run on a non-fx-application thread.
Is there any reason that the default implementation does not do this kind of short-circuiting?
Upvotes: 25
Views: 7183
Reputation: 15652
I've seen people calling EventQueue.invokeLater
from the EDT in Swing occasionally... it is, according to canon, a legitimate technique. So this is the same situation in JavaFX, unless I'm much mistaken.
I personally have my doubts about this technique, however. See this question: the chosen answer uses invokeLater
because selectAll()
needs to have all the current EDT events complete themselves before it is called: this solution does indeed ensure that selectAll
cannot be run before the other EDT code happening here.
But this answer, I maintain, has vulnerabilities. See the answer I have suggested (written in Jython, but should be understandable). Suppose someone sets "click count to start editing" to 1. Suppose, more worringly, something unpredictable happens between the invokeLater
and the selectAll
. Unless you are absolutely sure you have no alternative mechanism at all, or are absolutely sure that the events and objects of the two threads are completely "uncoupled", I personally would say avoid calling runLater
from the JavaFX thread.
Concurrency is always waiting to bite you. Best use such techniques with extreme caution, therefore!
Upvotes: 0
Reputation: 17707
When calling a function, and the function is called 'runLater', I would expect it to be run later, not now.
It seems to me that the implementation is doing the right thing, based on it's name, and it's documentation:
Run the specified Runnable on the JavaFX Application Thread at some unspecified time in the future.
This method, which may be called from any thread, will post the Runnable to an event queue and then return immediately to the caller. The Runnables are executed in the order they are posted. A runnable passed into the runLater method will be executed before any Runnable passed into a subsequent call to runLater
If you don't want the code to run later, don't ask for it to be run later. That is what you have essentially done with your code.
Upvotes: 16
Reputation: 328629
runLater
essentially places your Runnable in a queue for execution when the FX thread is available. The method can be accessed through non-FX threads. Imagine that some other threads have placed tasks in the runLater
queue, then calling runLater
again, whether from the FX thread or not, should place the new task at the tail of that queue.
With the short-circuiting you propose the previous tasks would basically have a lower priority which may not be desirable.
Upvotes: 18