我是Java的新手,但不是一般的编程。我在Windows Vista上使用Java 1.7.0_07。我试图弄清楚如何定期进行Swing Timer
滴答。
我注意到即使我设置了计时器延迟,并且我的actionPerformed
事件处理程序中没有任何内容,只有repaint()
方法,但计时器滴答不稳定甚至不准确。
我一直在寻找解决方案已经有一段时间了,看了看,John B Matthews博士相当整洁Kinetic Model example。在他的例子中,默认延迟是40mS,但计时器实际上是47mS +/- 1mS(偶尔从32mS到63mS的变化)。在actionPerformed
事件处理程序中花费的时间始终为0mS。这些结果源于将其代码作为应用程序运行。
如果你仔细观察'原子'的移动,那么口吃是显而易见的。我不明白是什么导致计时器以这种方式表现。 我的计算机上运行的最小Windows任务,但问题仍然存在。
是否有解决此问题的方法,还是只是Java的一个功能?
答案 0 :(得分:2)
我没有查看源代码或进行了彻底的调查。但我最好的猜测是,这是“一个特色”。
javax.swing.Timer
保证您在EDT上调用actionPerformed
方法。因此,每当Timer
达到其间隔时,它可能会在EDT上安排Runnable
,而后者将调用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());
}
}
它使用invokeLater
来安排Runnable
(最有可能使您不会像invokeAndWait
那样累积延迟)。但这意味着在计时器发布事件和实际触发actionPerformed
方法之间,EDT必须完成之前的任务。而且由于没有机制可以说:“嘿,EDT,现在就停止你正在做的事情,先完成我的工作”,没有机制可以避免延误。
也许您可以通过编写自己的Timer
使用SecondaryLoop
(在JDK7中提供)来获得更好的结果。但这是一个疯狂的猜测(我什么都没试过)