Issue
After working some while with JavaFX (Java8) I had found the concept of Properties very useful, allowing to use bean compliant variables to be bound to update on changes using a calculation tree e.g.:
class Person {
StringProperty name;
...
}
Person owner;
Person human;
owner.name().bind(human.name());
That allows to bind the GUI controls to the 'model', to automatically update on change.
So I also started to use the Property<T>
class in the model (my data objects I am doing my functional operations). But the JavaFX is a single threaded GUI implementation and setting such a Property linked to some GUI controls is only allowed, if it is done in the JavaFX thread. Else an exception will be thrown:
Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5
If I now start to write multithreaded code, I finally cannot use these Properties, even if I would love to. I cannot afford to encapsulate every change in a Platform.runLater()
call to pass it to the JavaFX thread.
Why does JavaFX not provide a thread-safe Property-Binding? (Or does it?)
Solution
Usability of JavaFX Properties outside the scope of the GUI view
JavaFX properties can definitely be used outside the scope of the GUI view. The basic Oracle JavaFX binding tutorial demonstrates this by creating a simple non-GUI java program which represents a Bill object where the total amount of the bill is exposed via a JavaFX property.
Why does JavaFX not provide a thread-safe Property-Binding? (Or does it?)
JavaFX does not support thread-safe property-binding. Probably the reason it does not support thread-safe property binding is because it does not need to.
Although JavaFX internally has a multi-threaded architecture with a render thread, an application thread, etc., externally to developers it really only exposes the single application thread. From a developer point of view, the developer codes their application as a single threaded system. The developer and the internal JavaFX implementations can just assume that everything is running in a single-threaded environment and coding is much simpler (see Multithreaded toolkits: A failed dream? and How to run two JavaFX UI in actual different threads for some background information on why this is the case). The property implementation, knowing that it is executing in such an environment, can also assume a single threaded architecture and skip potentially complicating in-built thread safety controls.
JavaFX does have the ability to spawn new threads for concurrent tasks (and any of the many concurrent facilities for standard Java development can also be used). The JavaFX concurrent API does have the ability to feed back property values (such as percentage of work done for task execution) in a thread safe manner, but that is done in a very specific way. The task API has specialized methods for modifying such properties (for example updateProgress
) and internally it uses thread checks and calls such as Platform.runLater
to ensure that code executes in a thread-safe manner.
So the JavaFX concurrency utilities don't achieve thread safety through in-built capabilities of the JavaFX property mechanism, but instead through explicit checks and calls inside the concurrency utility implementation for a very specific and limited set of properties. Even then, users have to be very careful when using these utilities as they often assume they can do things such as modify JavaFX GUI stage properties directly from within their concurrent tasks (even though documentation states that this should not be done); the same care needs to be taken if standard Java concurrent utilities like the java.util.concurrent
package is used rather than javafx.concurrent
.
It is possible that somebody could create an extension to the JavaFX property mechanism to better behave in thread safe environment, but nobody has created such an extension to date.
But the JavaFX is a single threaded GUI implementation and setting such a property linked to some GUI controls is only allowed, if it is done in the JavaFX thread.
The title of the question is "Usability of JavaFX properties outside the scope of the GUI view", but the particular issue you describe is a pretty specific subset of this, where I think you have the following combination of things:
- Properties on a model class.
- Properties in the model class can be read and written by either the JavaFX application thread or another user thread.
- Properties in the model class can be bound to active GUI elements such as the text in a TextField or a Label displayed on the screen.
Out of the box this isn't going to work because the JavaFX system assumes that properties of JavaFX GUI components are only read or modified on the JavaFX application thread. Also, internally to support binding and change listeners, the properties themselves need to maintain lists of listeners and bound properties to modify, and these lists likely assume that they will only be accessed or modified from a single thread. You can perhaps work around this by ensuring that every read or write goes on a single thread by wrapping invocations using Platform.runLater
to place the call on the JavaFX application thread, but from your question, this is exactly the kind of code which you are trying to avoid.
IMO for the use case I outlined in the points above, there is no other solution and Platform.runLater
wrapping must be used. You can potentially hide some of the complexity and boilerplate for the runLater calls by providing facade methods for property access and updates (similar to the JavaFX concurrent Task implementation), but such a system is likely a bit complex to implement (especially if you want to achieve a generic solution for the entire property/binding subsystem, rather than a specialized solution for a couple of specific properties like Task has).
What are JavaFX Properties for then?
The primary existing use-case is for supporting the binding-based GUI programming model for JavaFX GUI applications. JavaFX properties are used extensively with the JavaFX API and any application which uses that API.
As JavaFX is now included in all standard new Oracle JDK distributions, you can also use the properties from non-JavaFX programs. For instance, there are discussions on how to use these properties in JPA entity beans for instance. These non-JavaFX API use-cases are currently pretty rare in my experience.
Although the JavaFX properties and binding packages are within the javafx package namespace, they do not depend on other JavaFX packages. In a future modular JDK, such as Java 9 is proposed to be, it would be possible to have a Java program depend on a JavaFX property and binding module and not have any dependency on other modules for JavaFX GUI development (which might be useful for certain headless server systems, which are the primary deployment target for many Java applications).
A similar design was originally setup for other JavaFX facilities such as the timelines and transitions, such that a real-time Java system with time based scheduling of tasks via Timelines could make use of an animation/timeline module from JavaFX without depending upon the rest to the JavaFX system (but I am not sure that original design was carried through to today, so that might not really be possible anymore and the base pulse of the animation module is usually keyed to the minimum tick of 60fps perhaps locked at a screen refresh rate depending on the implementation).
JavaFX properties are not the generic solution to property management for Java, but they are probably the closest, most complete implementation of such a solution that I have seen so far. The ideal (as I recall the JavaFX project lead Richard Bair stating), is that property functionality would be built into the Java programming language, so the support comes not only from an API, but from improved language syntax. Perhaps some future Java version such as 10+ might have facilities such as these. Of course, that is an old discussion probably dating back to the beginning of the Java language and JDK specifications. Still, the world is not ideal and the JavaFX property mechanism (even with it's kind of bulky syntax and lack of in-built support for thread-safety), is still a useful tool for many applications. Also note that there are extensions for other languages as as Scala via ScalaFX which make the JavaFX property mechanism seem like it part of the syntax for that language.
Third Party libraries such as EasyBind, enhance the JavaFX property mechanism to better support programming paradigms such as functional reactive programming.
For now, if I wanted to make extensive use of property type facilities in a JavaFX program, I would probably base it on a combination of JavaFX properties and (potentially) EasyBind and ReactFX, as that seems to be the best solution for Java.
I would not use such a solution in a highly concurrent environment where threading is non-compartmentalized due to the lack of thread-safety support in the underlying libraries. Properties are based upon side-effect changes to mutable objects, which is a pretty difficult thing to reason about in multi-threaded programs. Even if the internal property implementation was modified to allow thread-safe read/writes on properties, I'm not sure that it would be such a great approach. For highly concurrent systems requiring a lot of communication between concurrent subtasks, use of another programming paradigm such as Actors (e.g. akka/erlang) or communicating sequential processes may be more appropriate than bound properties.
Answered By - jewelsea
Answer Checked By - David Goodson (JavaFixing Volunteer)