我很好奇javafx.concurent和Platform.runLater之间用于多线程JavaFx编程的区别是什么。
这是否意味着使用javafx.concurrent,我们可以拥有多个实际的绘图线程,或者它们最终都会在一个线程上结束?
E.g我喜欢的一件事是使用JavafX并同时摆动,因为它们都使用了两种不同的绘图线程。我会使用swing来处理繁重的内容(例如打开FileChooser)并使用JavaFX作为核心可视化内容,例如播放无缝的循环视频。然而,由于无头的异常错误,mac使得这一切变得不可能,所以一切都落在javafx上,这意味着在打开文件追踪器等事情时会有很多停顿。
如果我使用javafx.concurrent重写我的应用程序,我是否可以像使用Swing + JavaFX那样模仿2绘制线程体验?
答案 0 :(得分:14)
<强> Platform.runLater 强>
Worker
是Platform.runLater
的补充。
Platform.runLater
,并且您希望在JavaFX应用程序线程上运行某些逻辑。 Worker
,并希望在新线程上生成某些逻辑或(尤其)I / O,以免阻止JavaFX申请主题。 您永远不会想要在Platform.runLater
的{{1}}方法中进行网络I / O,但通常希望在run
&#39; s Worker
方法。
任务和服务
考虑使用Task的Service或Worker子类。这些是FutureTask的JavaFX包装器(又是Runnable)。 Worker提供了一个call方法来在后台线程上运行逻辑。它们维护执行status(通过线程安全回调通知JavaFX线程以进行状态更改)并通过value,message和exception属性返回调用结果。
利用call
和Task
javadoc示例中的设计模式,通过以下功能简化线程安全应用程序的创建:
一起使用Workers和Platform.runLater
此外,使用Service
和Task
与Service
的使用并不矛盾。例如,如果您有一个非常长的运行Platform.runLater
,您希望定期将部分结果返回到UI或缓冲区填充,然后在任务{{1}中执行Task
方法就是这样做的。
使用现有的线程系统
当您没有库提供的现有线程服务时,工作人员很有用,而是创建自己的线程以在后台执行。如果您有现有的线程服务,那么您将需要使用Platform.runLater
在JavaFX应用程序线程上执行逻辑。
小心编写多线程代码
请注意,即使您使用call
,仍需要知道自己在做什么。您仍然必须注意不要违反标准的JavaFX并发规则,例如永远不更新活动场景图上的节点(包括不更新活动场景图中的节点绑定的值 - 例如可观察的列表items支持ListView)。
回答您的一些补充问题
这是否意味着使用javafx.concurrent,我们可以拥有多个实际的绘图线程,或者它们最终都会在一个线程上结束?
JavaFX中只有一个渲染线程。您无法使用JavaFX并发制作更多渲染线程。您可以执行诸如从JavaFX线程创建节点或使用许多线程将像素设置为关闭屏幕WriteableImage或Canvas,但最终每个渲染操作都通过由您无法控制的JavaFX系统管理的单个线程。
如果我使用javafx.concurrent重写我的应用程序,我是否可以像使用Swing + JavaFX那样模仿2绘制线程体验?
没有。即使你可以,我也不认为这是可取的。使用这样的模型,很容易创建微妙的,难以调试的线程处理相关错误。您可能从这样的设置中看到的收益可能低于您希望或期望的收益。
参见相关文章,了解为什么有2个或更多&#34;画线&#34;可能是不可取的:
Java 8正在添加一个实验性命令行开关,以便为JavaFX应用程序线程和Swing事件调度线程使用相同的线程。主要原因是它简化了编程模型。
一切都落在javafx上,这意味着在打开文件追踪器等事情时会有很多停顿。
您的代码可能效率低下(例如在UI线程上执行I / O)导致暂停。
重物(例如打开FileChooser)
打开和渲染FileChooser并不重要。 JavaFX可以轻松处理此类操作,而不会降低性能。可能耗费时间的是与I / O相关的东西,例如以递归方式走大文件树以获取文件属性。在这种情况下你可以做的是为I / O生成一个线程,在Platform.runLater
中运行它,并通过Worker
定期将部分结果反馈给UI线程。这样的计划将运作良好。瓶颈不是绘图,因此拥有另一个绘图线程没有任何优势。瓶颈是缓慢的I / O系统,并且通过为I / O使用单独的线程来缓解这个瓶颈,这样主UI线程不会受到影响,并且用户在I / O发生时不会遇到UI冻结。