【问题标题】:Calling platform.runlater multiple times javafx多次调用platform.runlater javafx
【发布时间】:2020-06-11 18:00:12
【问题描述】:

我对在 javafx 中使用 Platform.runLater() 有点困惑,因为我得到 Platform.runLater() 会将可运行参数发送到线程队列,并按顺序执行它以防它被多次调用,以及 @987654324 @ 是单个 javafx 线程

在我的 javafx 应用程序中,我需要监听所有操作系统中的鼠标和键盘事件,而不仅仅是在 javafx 应用程序中

目前我正在创建两个Timeline

所以我正在做类似以下的事情:

class FirstTimeLineWrapperClass implements Runnable {
    public void run() {
      Timeline timeline1 = new Timeline(new KeyFrame(
                Duration.seconds(1),
                ae -> {
                    secondPassed++;
                }));

        timeline.setCycleCount(Animation.INDEFINITE);
        timeline.play();
    }
}

class SecondTimeLineWrapperClass implements Runnable {
    public void run() {
      Timeline timeline2 = new Timeline(new KeyFrame(
                Duration.seconds(1),
                ae -> {
                    secondPassed++;
                }));

        timeline.setCycleCount(Animation.INDEFINITE);
        timeline.play();
    }
}

然后我打电话:

Platform.runLater(new FirstTimeLineWrapperClass());
Platform.runLater(new SecondTimeLineWrapperClass());

以上内容有点混乱,但只是为了明确我的问题,

所以我们说可以这样做吗,上面的代码可能出了什么问题? 如果Platform.runLater() 将在单个javafx 线程中运行,那么上面的代码如何同时工作?

正如文档所述

警告:正在从 FX 运行时引用正在运行的时间轴。如果没有正确停止,无限时间线可能会导致内存泄漏。所有具有动画属性的对象都不会被垃圾回收。

【问题讨论】:

  • Timelines 不会同时运行,因为它们不会创建任何新线程,并且您创建的关键帧中的事件处理程序在 FX 应用程序线程上执行。实际上,所有发生的事情是 FX 应用程序线程知道它们并在适当的时间出现时执行任何必要的代码。您引用的评论非常不言自明:只要时间线在运行,就不能将其作为垃圾收集。
  • 当我在run这两个方法中加入print语句时,它们同时被打印出来了,这是如何解决的?
  • 您还期待什么其他行为?它们都(几乎)同时启动,并且每秒都执行它们的处理程序。因此,每一秒,两个关键帧处理程序都会执行。
  • 我期望的行为是第一个时间线将运行,一秒钟后下一个时间线将开始,因为它们都位于单个 javafx 线程中,所以我只是想知道这些处理程序是如何在 javafx 线程中工作,我的意思是它们是如何在单个线程中处理的,javafx 线程是否侦听时间线处理程序引发的事件,并在它们上执行某些操作,如果你能提供我一个完整的解释,我将不胜感激

标签: java javafx


【解决方案1】:

动画不会创建任何额外的线程,也不会在任何后台线程上运行。

您可以将 FX 应用程序线程视为一个循环,在伪代码中看起来像这样(实际细节要复杂得多):

while (applicationIsRunning()) {
    if (anyEventsNeedHandling()) {
        handleEvents();
    }
    processAnyRunnablesFromRunLaterQueue();
    if (timeToUpdateScene()) {
        if (animationsNeedProcessing()) {
            processAnimations();
        }
        updateScene();
    }
}

动画本质上的工作方式是,一个正在运行的动画在上面描述的主循环知道的某个地方注册自己。动画可以确定是否该做某事了——例如,在您的Timelines 中,关键帧每秒执行一次,因此Timeline 可以相对容易地报告一个或多个关键帧是否需要处理,并且如有必要,将调用事件处理程序。没有具体说明它的实际机制,但这是基本功能。

请注意,play() 方法只是启动动画(即注册它以供 FX 应用程序线程循环检查它)并立即退出。因此,在您的代码中,您在 FX 应用程序线程上快速连续启动两个 Timelines,它们将一个接一个地立即启动(实际上几乎同时启动)。

因此,您可以启动多个动画,它们不会阻塞 FX 应用程序线程。通常的规则适用于在 FX 应用程序线程上执行的代码,适用于任何关键帧处理程序中的代码:它不应该阻塞,也不应该花费很长时间来运行。

另请注意,如果您将可运行对象添加到稍后运行队列的速度超过了它们的执行速度,您将有效地阻塞 FX 应用程序线程,从而导致 UI 响应能力较差(或完全阻塞它)。

【讨论】:

    猜你喜欢
    • 2017-01-31
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 2015-05-31
    • 1970-01-01
    • 2014-12-17
    相关资源
    最近更新 更多