在使用JavaFX(Java8)工作一段时间之后,我发现Properties的概念非常有用,允许使用bean兼容变量绑定以使用计算树更新更改,例如:
class Person {
StringProperty name;
...
}
Run Code Online (Sandbox Code Playgroud)
Person owner;
Person human;
owner.name().bind(human.name());
Run Code Online (Sandbox Code Playgroud)
这允许将GUI控件绑定到"模型",以自动更新更改.
所以我也开始Property<T>在模型中使用该类(我的数据对象正在进行我的功能操作).但JavaFX是一个单线程GUI实现,只有在JavaFX线程中完成时,才允许设置链接到某些GUI控件的属性.否则将抛出异常:
Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5
Run Code Online (Sandbox Code Playgroud)
如果我现在开始编写多线程代码,我终于无法使用这些属性,即使我愿意.我无法承担将Platform.runLater()调用中的每个更改封装到JavaFX线程中的能力.
为什么JavaFX不提供线程安全的Property-Binding?(或者是吗?)
jew*_*sea 34
Java视图的可用性属性超出了GUI视图的范围
JavaFX属性绝对可以在GUI视图的范围之外使用.基本的Oracle JavaFX绑定教程通过创建一个简单的非GUI java程序来演示这一点,该程序表示一个Bill对象,其中通过JavaFX属性公开了账单的总金额.
为什么JavaFX不提供线程安全的Property-Binding?(或者是吗?)
JavaFX不支持线程安全的属性绑定.可能它不支持线程安全属性绑定的原因是因为它不需要.
尽管JavaFX内部具有多线程体系结构,其具有呈现线程,应用程序线程等,但在开发人员之外,它实际上只暴露单个应用程序线程.从开发人员的角度来看,开发人员将他们的应用程序编码为单线程系统.开发人员和内部JavaFX实现可以假设一切都在单线程环境中运行,并且编码更简单(参见多线程工具包:一个失败的梦想?以及如何在实际不同的线程中运行两个JavaFX UI以获取一些背景信息为什么会这样).知道它在这样的环境中执行的属性实现也可以采用单线程体系结构并跳过可能使内置线程安全控制复杂化的问题.
JavaFX确实能够为并发任务生成新线程(并且还可以使用标准Java开发的许多并发工具中的任何一个).JavaFX并发API确实能够以线程安全的方式反馈属性值(例如为任务执行完成的工作的百分比),但这是以非常特定的方式完成的.任务API具有用于修改此类属性的专用方法(例如updateProgress),并且在内部它使用线程检查和调用,Platform.runLater以确保代码以线程安全的方式执行.
因此,JavaFX并发实用程序不通过JavaFX属性机制的内置功能来实现线程安全,而是通过在并发实用程序实现中对一组非常特定且有限的属性进行显式检查和调用.即使这样,用户在使用这些实用程序时也必须非常小心,因为他们通常认为他们可以直接从并发任务中修改JavaFX GUI阶段属性(即使文档声明不应该这样做); 如果使用标准的Java并发实用程序(如java.util.concurrent包)而不是,则需要同样小心javafx.concurrent.
有人可能会创建JavaFX属性机制的扩展,以便在线程安全环境中更好地运行,但是迄今为止没有人创建过这样的扩展.
但JavaFX是单线程GUI实现,只有在JavaFX线程中完成时才允许设置链接到某些GUI控件的属性.
问题的标题是"GUI视图范围之外的JavaFX属性的可用性",但您描述的特定问题是其中非常特定的一部分,我认为您有以下组合:
开箱即用这是行不通的,因为JavaFX系统假定只在JavaFX应用程序线程上读取或修改JavaFX GUI组件的属性.此外,在内部支持绑定和更改侦听器,属性本身需要维护要修改的侦听器和绑定属性的列表,并且这些列表可能假设它们只能从单个线程访问或修改.您可以通过使用Platform.runLater将调用放在JavaFX应用程序线程上来包装调用来确保每个读取或写入都在单个线程上进行解决,但是从您的问题来看,这正是您要避免的代码类型.
IMO对于我在上述几点中概述的用例,没有其他解决方案,Platform.runLater必须使用包装.您可以通过为属性访问和更新提供Facade方法(类似于JavaFX并发Task实现)来隐藏runLater调用的一些复杂性和样板,但是这样的系统实现起来可能有点复杂(特别是如果您想要为整个属性/绑定子系统实现通用解决方案,而不是像Task这样的特定属性的专用解决方案.
什么是JavaFX属性呢?
主要的现有用例是支持JavaFX GUI应用程序的基于绑定的GUI编程模型.JavaFX属性广泛用于JavaFX API和使用该API的任何应用程序.
由于JavaFX现在包含在所有标准的新Oracle JDK发行版中,您还可以使用非JavaFX程序中的属性.例如,有关于如何在JPA实体bean中使用这些属性的讨论.根据我的经验,这些非JavaFX API用例目前非常少见.
尽管JavaFX属性和绑定包位于javafx包命名空间中,但它们不依赖于其他JavaFX包.在未来的模块化JDK(例如Java 9)中,有可能让Java程序依赖于JavaFX属性和绑定模块,并且不依赖于其他模块来进行JavaFX GUI开发(这可能对某些无头服务器系统,它们是许多Java应用程序的主要部署目标.
最初为其他JavaFX工具设置了类似的设计,例如时间轴和转换,这样通过时间轴基于时间的任务调度的实时Java系统可以利用JavaFX中的动画/时间轴模块,而不依赖于其余部分. JavaFX系统(但我不确定原始设计是否已经延续到今天,因此可能不再可能实现,并且动画模块的基本脉冲通常键入60fps的最小刻度,可能锁定在屏幕刷新率取决于实施).
JavaFX属性不是Java的属性管理的通用解决方案,但它们可能是迄今为止我见过的最接近,最完整的解决方案.理想的(我记得JavaFX项目负责人Richard Bair所说的)是,属性功能将构建到Java编程语言中,因此支持不仅来自API,还来自改进的语言语法.也许未来的某些Java版本(例如10+)可能具有这些设施.当然,这是一个古老的讨论,可能追溯到Java语言和JDK规范的开头.尽管如此,世界并不理想,JavaFX属性机制(即使它具有庞大的语法和缺乏内置的线程安全支持)仍然是许多应用程序的有用工具.另请注意,Scala通过ScalaFX可以扩展其他语言,这使得JavaFX属性机制看起来像是该语言语法的一部分.
诸如EasyBind之类的第三方库增强了JavaFX属性机制,以更好地支持编程范例,例如功能反应式编程.
目前,如果我想在JavaFX程序中广泛使用属性类型工具,我可能会将它基于JavaFX属性和(可能)EasyBind和ReactFX的组合,因为这似乎是Java的最佳解决方案.
我不会在高度并发的环境中使用这样的解决方案,因为底层库中缺少线程安全支持,线程非划分.属性基于对可变对象的副作用更改,这在多线程程序中是很难推理的.即使修改了内部属性实现以允许对属性进行线程安全读/写,我也不确定它是否会是一个很好的方法.对于需要在并发子任务之间进行大量通信的高度并发系统,使用其他编程范例(如Actors(例如akka/erlang))或传递顺序进程可能比绑定属性更合适.
| 归档时间: |
|
| 查看次数: |
4846 次 |
| 最近记录: |