【问题标题】:Usage of JavaFX Platform.runLater and access to UI from a different threadJavaFX Platform.runLater 的使用和从不同线程访问 UI
【发布时间】:2013-02-16 02:41:39
【问题描述】:

我有几个关于Platform.runLater 的问题。我有一个 JavaFX 应用程序类。在这个类中,我运行一个线程(线程从网络套接字读取数据)。

现在当我在线程内创建一个新的Stage 时,系统会抛出一个执行(JavaFX 事件调度程序线程和我的 netork-read 线程不一样) - 我理解这种行为。

但另一方面是,我将网络阅读器中的文本附加到现有的 TextArea 或添加/删除 ListView<String> 中的一些项目 - 这不会引发异常 - 为什么?我认为 JavaFX 是单线程的(ui 库部分)。这是否与 Swing 中的相同:有时它可以工作,有时你只是垃圾(因为 EDT)?

我的问题:

  • JavaFX 事件调度线程什么时候抛出异常,什么时候不抛出?
  • 有什么好的文档吗?
  • 是否有更简单(更短、更简洁)的方式来使用Platform.runLaterrun() 方法?结合try catch(或multiple catch),看起来很奇怪

我知道Platform.runLater 在线程中的使用不是很好(设计解决方案)

【问题讨论】:

  • Or is this the same thing as in Swing: Sometimes it works and sometimes you have just garbage? 请问你在说什么,Swing GUI 的所有更新都必须在 EDT 上完成,GUI 单一威胁在大多数情况下是优势,适用于各种编程语言的大量 GUI 框架
  • 是的,我的意思是 Swing 中的 EDT(只需在 EDT 上下文中使用 UI)。我的意思是,当您在 EDT 之外访问 Swing UI 时,有时它会起作用,有时则不起作用
  • 请在您的问题中包含一个演示In combination with a try catch (or multiple catch), it looks very strange的代码示例。

标签: java multithreading javafx-2 event-dispatch-thread


【解决方案1】:

Alexander 的回答抓住了与您的问题相关的最重要的一点。

此答案提供了一些补充信息。

JavaFX 事件调度线程什么时候抛出异常,什么时候不抛出?

JavaFX 系统并不总是检查对影响活动场景图的对象的访问是否正确地限制在 JavaFX 线程中。最终,确保这种线程安全是 JavaFX 应用程序程序员的责任,而不是 JavaFX 系统。在 JavaFX 中执行多线程编程时必须非常小心,否则应用程序行为可能会失败或变得不可预测。

有什么好的文档吗

试试 JavaFX 教程:Concurrency in JavaFX

有没有更简单(更短、更简洁)的方式来使用 Platform.runLater 和 run() 方法?

没有。 Platform.runLater 就是这么简单。


顺便说一句。 . .

任务和服务

考虑使用WorkerTaskService 子类。这些是FutureTask(又是Runnable)的JavaFX 包装器。 Worker 提供了一个call 方法来在后台线程上运行逻辑。它们维持status 的执行(通过线程安全回调通知JavaFX 线程以进行状态更改)并通过valuemessageexception 属性返回调用结果。

利用TaskService javadoc 示例中的设计模式来简化线程安全应用程序的创建,并具有以下特性:

  • 为 UI 更新异步获取数据。
  • 任务进度的定期消息更新。
  • 正在构建尚未附加到显示场景的节点图。
  • 通过进度条等监控进度。

WorkerPlatform.runLater 互补。当您在 JavaFX 应用程序线程之外执行并且想要在 JavaFX 应用程序线程上运行一些逻辑时,请使用 Platform.runLater。当您在 JavaFX 应用程序线程上运行并希望在新线程上产生一些逻辑或(特别是)I/O 时使用Worker,这样您就不会阻塞 JavaFX 应用程序线程。您永远不会希望在 Platform.runLaterrun 方法中进行网络 I/O,但通常希望在 Workercall 方法中进行。

此外,TaskService 的使用与 Platform.runLater 的使用并非不兼容。例如,如果您有一个运行时间很长的Task,您希望定期将部分结果返回到UI 或作为缓冲区填充,那么在任务的call 方法中执行Platform.runLater 就是这样做的方法。

当您没有库提供的现有线程服务,而是创建自己的线程以在后台执行时,Worker 很有用。如果您有一个现有的线程服务,那么您将需要使用Platform.runLater 在 JavaFX 应用程序线程上执行逻辑。

请注意,即使您使用Worker,您仍然需要知道自己在做什么。您仍然必须注意不要违反标准 JavaFX 并发规则,例如从不更新活动场景图中的节点(包括不更新活动场景图中的节点绑定到的值 - 例如 @987654332 的可观察列表@支持ListView)。

【讨论】:

  • 好的,非常感谢您的精彩解释 - 我需要一些时间来阅读这篇文章并进行一些代码测试
  • "...包括不更新活动场景图中的节点绑定到的值 - 例如支持 ListView 的可观察项目列表"。您能否再解释一下,或者提供一个包含更多详细信息的链接?
  • 这是一个有价值的问题,但完整的答案超出了这个问题的范围。请创建一个新问题,如果写得好,我相信它至少会收到一两个非常好的答案。您可以在问题中提供此答案的链接并引用。求一些代码示例提供具体演示。
【解决方案2】:

“这不会引发异常 - 为什么?”因为并非所有此类情况都被咳嗽...可能是出于性能考虑,可能只是缺少功能。

与 JavaFX 对象的所有交互(包括创建)必须在 JFX 线程上完成,如果您想从另一个线程访问这些 JFX 对象 - 使用 runLater 或 runAndWait 方法。如果它现在不抛出异常,它可能会在未来开始抛出异常。与 JFX 对象的任何交互都可能导致后续的动作和事件,这将被某些线程检查器咳出 - 你不能确定。

我不认为,这方面有什么好的文档 - 只是一个简单的规则 - 使用 runLater 或 runAndWait。

更短更简洁的方式 - 将在 JDK 8 中使用 Lambda 提供。

【讨论】:

  • 好的,谢谢。很高兴知道 - 我将使用 Platform.runLater。关于 JDK 8 - 遗憾的是我不能等到 2013 年 9 月 :(
  • 你可以下载它的预览。实际上,您可以开始使用 JDK 8 来承担风险。据我所知,它包含 lambda。 jdk8.java.net/download.html
猜你喜欢
  • 2015-02-03
  • 2018-05-24
  • 2014-12-17
  • 2014-05-11
  • 1970-01-01
  • 2012-11-26
  • 2019-04-10
  • 1970-01-01
相关资源
最近更新 更多