6

我们希望每 1000 秒运行一次任务(比如说)。

所以我们有

timer.scheduleAtFixedRate(task, delay, interval);

大多数情况下,这工作正常。但是,这是一个嵌入式系统,用户可以更改实时时钟。如果他们在我们设置计时器后将其设置为过去的时间,那么计时器似乎直到原始实时日期/时间才会执行。因此,如果他们将其设置回 3 天,则计时器不会执行 3 天:(

这是允许的行为,还是 Java 库中的缺陷?Oracle javadocs 似乎没有提到任何关于系统时钟基础值的依赖关系。

如果允许,我们如何发现这个时钟变化并重新安排我们的计时器?

4

2 回答 2

18

查看 for Java 1.7 的源代码Timer,它似乎System.currentTimeMillis()用于确定任务的下一次执行。

但是,查看 的来源ScheduledThreadPoolExecutor,它使用System.nanoTime().

这意味着如果您使用 one 代替 a ,您将看不到这种行为Timer。例如,要创建一个,请使用Executors.newScheduledThreadPool().

为什么您看不到这种行为是因为文档中System.nanoTime()所说的:

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值表示自某个固定但任意的原始时间以来的纳秒[强调我的]。

至于这是否是一个错误Timer,也许......

请注意,与 a 不同ScheduledExecutorService,aTimer支持绝对时间,也许这解释了它对 ; 的使用System.currentTimeMillis()。此外,Timer自 Java 1.3 以来一直存在,而System.nanoTime()仅出现在 1.5 中。

但是使用的结果System.currentTimeMillis()Timer对系统日期/时间很敏感......这在javadoc中没有记录。

于 2013-07-11T08:18:30.037 回答
5

这里报道http://bugs.sun.com/view_bug.do?bug_id=4290274

类似地,当系统时钟设置为较晚的时间时,任务可能会运行多次而没有任何延迟以“赶上”错过的执行。当计算机设置为待机/休眠并恢复应用程序时,就会发生这种情况(这就是我发现的方式)。

通过暂停计时器线程并恢复它,在 Java 调试器中也可以看到这种行为。

于 2013-07-31T08:40:04.850 回答