1

我对 Java 比较陌生,但一般不会编程。我在 Windows Vista 上使用 Java 1.7.0_07。我试图弄清楚如何Timer定期使 Swing 滴答作响。

我注意到,即使我设置了计时器延迟,并且在我的actionPerformed事件处理程序中除了一个repaint()方法之外什么都没有,计时器滴答声也不稳定甚至不准确。

我一直在寻找解决方案一段时间,并查看了 John B Matthews 博士相当简洁的动力学模型示例。在他的示例中,默认延迟为 40mS,但计时器实际上以 47mS +/- 1mS 计时(偶尔会出现从 32mS 到 63mS 的变化)。在他的actionPerformed事件处理程序中花费的时间总是 0mS。这些结果来自于将他的代码作为应用程序运行。

如果您仔细观察“原子”的移动,则口吃很明显。我不明白是什么导致计时器以这种方式运行。我的计算机上运行了最少的 Windows 任务,但问题仍然存在。

是否有解决此问题的方法,或者这只是 Java 的一个功能?

4

1 回答 1

2

我没有看源代码,也没有做彻底的调查。但我最好的猜测是这是“一个功能”。

javax.swing.Timer保证您actionPerformed在 EDT 上调用该方法。因此,每当Timer达到其间隔时,它可能会Runnable在 EDT 上安排 a ,而后者又会调用该actionPerformed方法。但是,如果 EDT 在那个确切时刻很忙(例如重新绘制),它就不能执行那个Runnable.

所以一个小的延迟是不可避免的......

刚刚检查了源代码,似乎我最初的猜测是正确的

void post() {
     if (notify.compareAndSet(false, true) || !coalesce) {
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
             public Void run() {
                 SwingUtilities.invokeLater(doPostEvent);
                 return null;
            }
        }, getAccessControlContext());
    }
}

它使用 aninvokeLater来安排Runnable(很可能是这样您就不会像 an 那样累积延迟invokeAndWait)。但这意味着在计时器发布事件和actionPerformed实际触发方法之间,EDT 必须完成他之前的任务。而且由于没有机制可以说:“嘿 EDT,停止你现在正在做的事情,先执行我的工作”,因此没有机制可以避免延迟。

也许您可以通过编写自己的Timer使用SecondaryLoop(在 JDK7 中可用)来获得更好的结果。但这是一个疯狂的猜测(我什么都没试过)

于 2012-11-18T09:39:55.433 回答