为什么Platform.runLater不检查当前是否在JavaFX线程上?

23

在使用JavaFX 8时,我们需要通过Platform.runLater来运行与GUI的交互,否则如果从另一个线程运行,它们将抛出异常。

但是,Platform.runLater的实现从未检查它当前是否在JavaFX线程上。

我编写了以下方法:

public static void runSafe(final Runnable runnable) {
    Objects.requireNonNull(runnable, "runnable");
    if (Platform.isFxApplicationThread()) {
        runnable.run();
    }
    else {
        Platform.runLater(runnable);
    }
}

这确保它永远不会在非fx应用程序线程上运行。

是否有任何原因导致默认实现没有进行此类短路处理?


2
在StackOverflow上看到好问题和好答案真是太棒了。 - jewelsea
我希望这个方法能够被添加到“平台”中,因为在90%的情况下,这就是我所需要的。 - Stefan Endrullis
3个回答

18

runLater本质上是将您的Runnable放入队列中,在FX线程可用时执行。该方法可通过非FX线程访问。假设其他一些线程已将任务放在runLater队列中,则无论从FX线程还是非FX线程调用runLater,都应将新任务放在该队列的尾部。

您提出的短路方案会使之前的任务基本上具有较低的优先级,这可能并不理想。


总的来说,我同意这是任何runLater的副作用,但这是设计上的缺陷。OP在他的考虑中是正确的,但不幸的是它就是这样工作的。 - Thomas

16

当调用一个名为'runLater'的函数时,我期望它会稍后执行,而不是立即执行。

根据它的名称和文档,我认为它的实现是正确的:

在将来的某个未指定的时间,在JavaFX应用程序线程上运行指定的Runnable。

这个方法可以从任何线程调用,它会将Runnable发布到一个事件队列,然后立即返回给调用者。Runnables按照发布的顺序执行。传递给runLater方法的Runnable将在任何传递给后续调用runLater的Runnable之前执行

如果你不想让代码稍后运行,那就不要请求它稍后运行。这就是你的代码本质上所做的事情。


0

我曾经看到有人偶尔在Swing中从EDT调用EventQueue.invokeLater... 根据规范,这是一种合法的技术。所以在JavaFX中也是同样的情况,除非我大错特错。

然而,我个人对这种技术持怀疑态度。请参见this question:所选答案使用invokeLater,因为selectAll()需要在调用之前完成所有当前的EDT事件:这个解决方案确实确保了在此处发生的其他EDT代码之前不能运行selectAll

但是我认为这个答案有漏洞。请看我建议的答案(用Jython编写,但应该可以理解)。假设有人将“点击计数以开始编辑”设置为1。更令人担忧的是,在invokeLaterselectAll之间发生了不可预测的事情。除非您绝对确定没有任何替代机制,或者绝对确定两个线程的事件和对象完全“解耦”,否则我个人会建议避免从JavaFX线程调用runLater

并发始终在等待着咬你。因此最好极度谨慎地使用这些技术!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接