Java中的定时器类(Timer class)如何受系统时钟影响?

9

这个在SO上高票的回答详细阐述了TimerScheduledThreadPoolExecutor之间的区别,其中列举了以下差异:

Timer可能对系统时钟的变化产生敏感,而ScheduledThreadPoolExecutor不会对其产生影响。

以上内容来自于伟大的书籍《Java Concurrency in Practice》。

除了上述提到的内容,我理解了该答案中提到的其他点。但是,什么意思是说Timers可以受到系统时钟的影响,而ScheduledThreadPoolExecutors不会呢?


请查看此链接:https://dev59.com/cnTYa4cB1Zd3GeqPtVWk - Juned Ahsan
3个回答

10

Timer 使用的是System.currentTimeMillis(),它表示的是挂钟时间,不应该用于检查相对时间,如确定某个任务运行了多长时间或在这种情况下执行任务前需要延迟多长时间。 System.currentTimeMillis() 受到诸如自动调整系统时钟甚至手动更改系统时钟等因素的影响。因此,如果您调用两次并检查时间差,甚至可能得到负数。

另一方面,System.nanoTime() 专门用于测量经过的时间,应该用于这种类型的任务。


系统时钟的自动调整是什么意思? - Geek
1
@Geek:系统时钟随着时间的推移可能会略微偏差,需要进行小调整以保持正确(例如,如果它正在与中央时间服务器同步)。我相信还可以进行一些调整来处理像闰秒之类的事情。 - ColinD

5

Timer使用System.currentTimeMillis()来确定任务的下一次执行。

然而ScheduledThreadPoolExecutor使用System.nanoTime()

nanoTime()方法只能用于测量经过的时间,与任何其他系统或挂钟时间概念无关。

System.currentTimeMillis()对系统时钟非常敏感。

System.nanoTime()不受系统时钟影响,因为它是测量经过的时间。

Java文档:System.nanoTime()

此方法只能用于测量经过的时间,与任何其他系统或挂钟时间概念无关。返回值表示自某个固定但任意的时间(可能在未来),以纳秒为单位经过的时间(因此值可能为负数)。


文档还指出,参考点在 JVM 运行时不会改变,除非它运行超过约 292 年,但参考点在本地和远程 JVM 实例之间可能会有所不同。 - nexus_2006
1
@nexus_2006 这对本地机器上的任务调度有什么影响吗? - Narendra Pathai
我只是觉得有趣的是,当你使用ThreadPoolExecutor类时,我想它并没有什么区别。我对那个类不是很熟悉,但看起来你只能设置延迟时间,而不能设置精确的时钟时间,但我可能错了。当直接在你的应用程序中使用nanoTime()时,它不是一个时间,只是一个标记。文档说它的准确性不比currentTimeMillis()更高。只是觉得这些差异很有趣。 - nexus_2006

1
查看源代码,Timer类使用System.currentTimeMillis()来安排任务。ScheduledThreadPoolExecutor则使用System.nanoTime()currentTimeMillis()通常使用操作系统时钟,即跟踪当前日期/时间的时钟。nanoTime()则通常使用高分辨率硬件时钟。
如果您将操作系统时钟向后调整一小时,则currentTimeMillis()应该会反映出这一点,而nanoTime()则不应该。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接