Java 摆动计时器的滴答声不稳定,不规则

Java 摆动计时器的滴答声不稳定,不规则,java,swing,timer,delay,Java,Swing,Timer,Delay,我对Java相当陌生,但不是一般的编程。我正在Windows Vista上使用Java 1.7.0_07。我正在试图弄清楚如何使Swing计时器定期运行 我注意到,即使我设置了计时器延迟,并且在我的actionPerformed事件处理程序中除了repaint()方法之外没有任何内容,但计时器的滴答声并不稳定,甚至不准确 一段时间以来,我一直在寻找一个解决方案,并且已经研究过约翰·马修斯博士,他相当整洁。在他的例子中,默认延迟为40mS,但计时器实际的滴答声为47mS+/-1mS(偶尔会有32m

我对Java相当陌生,但不是一般的编程。我正在Windows Vista上使用Java 1.7.0_07。我正在试图弄清楚如何使Swing
计时器定期运行

我注意到,即使我设置了计时器延迟,并且在我的
actionPerformed
事件处理程序中除了
repaint()
方法之外没有任何内容,但计时器的滴答声并不稳定,甚至不准确

一段时间以来,我一直在寻找一个解决方案,并且已经研究过约翰·马修斯博士,他相当整洁。在他的例子中,默认延迟为40mS,但计时器实际的滴答声为47mS+/-1mS(偶尔会有32mS到63mS的变化)。在他的
actionPerformed
事件处理程序中花费的时间始终为0毫秒。这些结果是作为应用程序运行他的代码得到的

如果你仔细观察“原子”的运动,口吃是显而易见的。我不明白是什么原因导致计时器出现这种情况。 我的计算机上运行的windows任务最少,但问题仍然存在


这个问题有解决方案吗?或者这只是Java的一个特性吗?

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

javax.swing.Timer
保证在EDT上调用
actionPerformed
方法。因此,每当
计时器
达到其间隔时,它可能会在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());
    }
}
void post(){
if(notify.compareAndSet(false,true)| |!合并){
AccessController.doPrivileged(新的PrivilegedAction(){
公开募捐{
SwingUtilities.invokeLater(doPostEvent);
返回null;
}
},getAccessControlContext());
}
}
它使用
调用器
来调度
可运行的
(最有可能的情况是,这样您就不会像使用
invokeAndWait
那样累积延迟)。但这意味着从计时器发布事件到实际触发
actionPerformed
方法之间,EDT必须完成之前的任务。由于没有任何机制可以说:“嘿,EDT,停止你现在正在做的事情,先完成我的工作”,因此没有任何机制可以避免延迟


也许您可以通过编写自己的
计时器
来获得更好的结果,该计时器使用
第二个循环
(在JDK7中提供)。但这是一个胡乱猜测(我什么也没试过)

“动力学模型示例”当您看到所描述的行为时,它是作为小程序还是应用程序运行的?我倾向于在应用程序中进行测试。是的,我认为不准确性是
定时器的一个特点。安德鲁,看一看。我把它作为应用程序运行。(编辑我的帖子以反映这一方面。)我理解您对问题的一般描述,尽管我不理解您给出的代码示例。动力学模型代码使用“invokeLater”,但仅用于启动整个应用程序。计时器稍后设置。actionPerformed方法中的时间为0毫秒,因此足够快。在我自己的代码中,定时器设置为以2000mS的间隔启动,我的数据表明定时器实际启动时间约为2014mS(+/-5mS)。我的代码只不过重新绘制了一个JFrame,其中包含一个空的JPanel。从2000mS到14mS,更不用说变化是一个巨大的时间滞后,当我的CPU运行在2.5GHz时。我看了SecondaryLoop函数,但我怀疑它是否能为我工作,因为它依赖于正在生成的事件(如按下按钮)。此外,它在执行循环时阻塞当前线程。也许你可以再解释一点(API文档告诉我的)。我想要得到一个相当精确和有规律的计时器滴答声的背景是基于创建一个不抖动的游戏循环。我不确定其他人是如何做到这一点的,但我似乎无法理解。(这个问题让我想起了微软未记录的行为,需要反复尝试才能解决。除了这个问题,我不知道我能做些什么来让计时器按照API文档运行)@user1756090该代码段是调度
ActionListener
触发器的
Timer
类的源代码的一部分。因此,它不是“问题的解决方案”中的代码示例。问题不在于执行
操作的速度有多快。问题是,在EDT上调度某些内容不会立即调用它,因为EDT可能很忙