首页 文章

使用JavaFX Platform.runLater并从不同的线程访问UI

提问于
浏览
8

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

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

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

我的问题:

  • JavaFX事件调度程序线程何时抛出异常,何时抛出异常?

  • 有关于此的任何好文件

  • 使用 Platform.runLater 方法使用 Platform.runLater 是否更简单(更简洁,更清晰)?结合try catch(或多次捕获),它看起来很奇怪

我知道在一个线程中使用 Platform.runLater 并不是那么好(设计解决方案)

2 回答

  • 16

    “这不会例外 - 为什么?”因为并非所有这些情况都是正确的......可能,由于性能方面的考虑,可能只是一个错过的功能 .

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

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

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

  • 10

    亚历山大的答案捕获了关于你的问题的最重要的观点 .

    这个答案提供了一些补充信息 .

    JavaFX事件调度程序线程何时抛出异常,何时抛出异常?

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

    这是关于此的任何好文件吗?

    试试JavaFX教程:Concurrency in JavaFX .

    使用run()方法使用Platform.runLater是否更简单(更简洁,更清晰)?

    没有. Platform.runLater 就像它得到的一样简单 .


    作为旁白 . . .

    Task and Service

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

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

    • 异步获取UI更新的数据 .

    • 任务进度的定期消息更新 .

    • 构造尚未附加到显示场景的节点图 .

    • 通过进度条等监控进度

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

    此外,使用 TaskService 与使用 Platform.runLater 不兼容 . 例如,如果你想要将部分结果定期返回到UI或者作为缓冲区填充而长时间运行 Task ,那么在任务的 call 方法中执行 Platform.runLater 就是这样做的方法 .

    当您没有库提供的现有线程服务时,工作人员很有用,而是创建自己的线程以在后台执行 . 如果您有现有的线程服务,则需要使用 Platform.runLater 在JavaFX应用程序线程上执行逻辑 .

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

相关问题