我们希望每1000秒运行一次任务(比方说)。
所以我们有
timer.scheduleAtFixedRate(task, delay, interval);
大多数情况下,这很好。但是,这是一个嵌入式系统,用户可以更改实时时钟。如果他们在我们设置定时器之后将其设置为过去的时间,则计时器似乎直到原始实时日期/时间才执行。因此,如果他们将其设置为3天,则计时器不会执行3天:(
这是允许的行为,还是Java库中的缺陷? Oracle javadocs似乎没有提及有关依赖性的任何信息,也没有提及系统时钟的基础值。
如果允许,我们如何发现这个时钟变化并重新安排我们的计时器?
答案 0 :(得分:13)
查看Java 1.7的Timer
的来源,似乎使用System.currentTimeMillis()
来确定下一次执行任务。
但是,查看ScheduledThreadPoolExecutor
的来源,它会使用System.nanoTime()
。
这意味着如果您使用一个代替Timer
,则不会看到该行为。要创建一个,请使用Executors.newScheduledThreadPool()
。
为什么您不会看到此行为是因为System.nanoTime()
的文档说明了什么:
此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。 返回的值表示纳秒,因为某些固定但任意的原始时间 [强调我的]。
至于这是Timer
中的错误,也许......
请注意,与ScheduledExecutorService
不同,Timer
支持绝对时间,也许这解释了它对System.currentTimeMillis()
的使用;此外,Timer
自Java 1.3以来一直存在,而System.nanoTime()
仅出现在1.5。
但使用System.currentTimeMillis()
的结果是Timer
对系统日期/时间敏感...而javadoc中没有记录。
答案 1 :(得分:3)
此处报告http://bugs.sun.com/view_bug.do?bug_id=4290274
类似地,当系统时钟设置为稍后时间时,任务可以多次运行而没有任何延迟以“赶上”错过的执行。当计算机设置为待机/休眠状态并恢复应用程序时,就会发生这种情况(这就是我发现的)。
通过挂起计时器线程并恢复它,也可以在Java调试器中看到此行为。