【问题标题】:What should Timertask.scheduleAtFixedRate do if the clock changes?如果时钟发生变化,Timertask.scheduleAtFixedRate 应该怎么做?
【发布时间】:2023-03-16 06:23:02
【问题描述】:

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

所以我们有

timer.scheduleAtFixedRate(task, delay, interval);

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

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

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

【问题讨论】:

  • 如果你将时间提前 3 天,它会执行无限次(不完全是,但你知道我的意思)试图赶上的时间!!

标签: java clock timertask system-clock


【解决方案1】:

查看 Java 1.7 的 Timer 的来源,似乎是使用 System.currentTimeMillis() 来确定任务的下一次执行。

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

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

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

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

至于这是否是Timer的bug,或许……

请注意,与ScheduledExecutorService 不同,Timer 支持绝对时间,这可能解释了它使用System.currentTimeMillis() 的原因;此外,Timer 自 Java 1.3 以来就已存在,而 System.nanoTime() 仅出现在 1.5 中。

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

【讨论】:

  • +1 正在查看源代码并得出相同的结论。它可能应该记录得更好一些。
  • 看起来正是我需要的,但它是 Java 1.5 或更高版本。我们必须使用 1.4 :( Backports (of JSR-166) 存在,但仍然依赖某种不受日期/时间设置更改影响的实时时钟。仍在寻找我们的环境中是否存在这样的东西...
  • 呃,抱歉,我根本不做 1.4 :( 我知道一个名为 backport-util-concurrent 的包,但确实 System.nanoTime() 是另一回事......如果 1.4 我猜只有本机代码可以提供。
【解决方案2】:

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

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

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

【讨论】:

  • "同样,当系统时钟设置为较晚的时间时,任务可能会运行多次"。这似乎取决于。我们有一个 IBM j9 系统,这似乎没有发生,但它会触发一次,一段时间后与重复周期没有明显联系,然后按预期重复。不过,我们还没有完全描述这一点。我们正在考虑迁移到 ScheduledExecutorService
  • 好吧,这很有趣。我们在 Windows 上使用 Oracle Java。
猜你喜欢
  • 2022-11-12
  • 2022-07-29
  • 2014-01-06
  • 2012-08-29
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
相关资源
最近更新 更多