Platform.runLater
AWorker
与 互补Platform.runLater
。
Platform.runLater
当您在 JavaFX 应用程序线程之外执行并且想要在 JavaFX 应用程序线程上运行一些逻辑时使用。
- 当
Worker
您在 JavaFX 应用程序线程上运行并希望在新线程上产生一些逻辑或(尤其是)I/O 时使用 a,这样您就不会阻塞 JavaFX 应用程序线程。
您永远不会想在 a 的方法中进行网络 I/O Platform.runLater
,run
但通常希望在 aWorker
的call
方法中进行。
任务与服务
考虑使用Worker的Task或Service子类。这些是FutureTask的 JavaFX 包装器(又是Runnable)。Worker 提供了一个调用方法来在后台线程上运行逻辑。它们维护执行状态(通过向 JavaFX 线程发出线程安全回调通知以进行状态更改)并通过value、message和exception属性返回调用结果。
Task
利用和javadoc 示例中的设计模式Service
来简化线程安全应用程序的创建,这些应用程序具有以下特性:
- 为 UI 更新异步获取数据。
- 任务进度的定期消息更新。
- 构建尚未附加到显示场景的节点图。
- 通过进度条等监控进度。
一起使用 Workers 和 Platform.runLater
此外,Task
andService
的使用与Platform.runLater
. 例如,如果您有一个很长的运行Task
时间,您希望定期或在缓冲区填充时将部分结果返回到 UI,那么Platform.runLater
在任务的call
方法中执行就是执行此操作的方法。
使用现有的线程系统
当您没有库提供的现有线程服务,而是创建自己的线程以在后台执行时,工作者很有用。如果您有一个现有的线程服务,那么您将需要使用Platform.runLater
在 JavaFX 应用程序线程上执行逻辑。
小心编写多线程代码
请注意,即使您使用Worker
. 您仍然必须注意不要违反标准 JavaFX 并发规则,例如从不更新活动场景图中的节点(包括不更新活动场景图中的节点绑定到的值 - 例如支持的可观察项目列表一个列表视图)。
回答你的一些附加问题
这是否意味着使用 javafx.concurrent,我们可以有多个实际的绘图线程,还是最终都在一个线程上?
JavaFX 中只有一个渲染线程。您不能使用 JavaFX 并发创建更多渲染线程。您可以使用许多线程在 JavaFX 线程之外创建节点或将像素设置为屏幕外的 WriteableImage 或 Canvas,但最终每个渲染操作都通过由 JavaFX 系统管理的单个线程,您无法控制该线程。
如果我使用 javafx.concurrent 重写我的应用程序,我是否可以像以前使用 Swing + JavaFX 那样模仿 2 绘制线程体验?
不,即使你可以,我也不认为这是可取的。使用这样的模型,很容易创建微妙的、难以调试的线程处理相关错误。您可能从这种设置中看到的收益可能比您希望或预期的要少。
请参阅相关文章,了解为什么不建议使用 2 个或更多“绘制线程”:
Java 8 正在添加一个实验性命令行开关,以便为 JavaFX 应用程序线程和 Swing 事件调度线程使用相同的线程。这样做的主要原因是它简化了编程模型。
一切都落在了 javafx 上,这意味着在做诸如打开文件选择器之类的事情时会有很多停顿。
也许您的代码效率低下(例如在 UI 线程上执行 I/O)导致了暂停。
繁重的东西(例如打开 FileChooser)
打开和渲染 FileChooser 并不繁重。JavaFX 可以轻松处理此类操作而不会降低性能。耗时的是与 I/O 相关的东西,例如递归地遍历大型文件树以获取文件属性。在这种情况下,您可以做的是为 I/O 生成一个线程,在 a 中运行它,Worker
并定期通过Platform.runLater
. 这样的方案会运作良好。瓶颈不是绘图,因此拥有另一个绘图线程没有任何优势。瓶颈是缓慢的 I/O 系统,通过使用单独的 I/O 线程来缓解这个瓶颈,这样主 UI 线程不会受到影响,并且用户不会在 I/O 发生时遇到 UI 冻结。