【发布时间】:2011-08-15 21:34:43
【问题描述】:
出于诊断目的,我希望能够在长时间运行的服务器应用程序中检测系统时钟的变化。由于System.currentTimeMillis() 基于挂钟时间,System.nanoTime() 基于独立于挂钟时间(*)的系统计时器,我想我可以使用这些值之间差异的变化来检测系统时间变化。
我编写了一个快速测试应用程序,以查看这些值之间的差异有多稳定,令我惊讶的是,这些值立即以每秒几毫秒的水平出现差异。有几次我看到了更快的分歧。这是在带有 Java 6 的 Win7 64 位桌面上。我还没有在 Linux(或 Solaris 或 MacOS)下尝试过这个测试程序来查看它的性能。对于此应用程序的某些运行,差异是正的,对于某些运行,它是负的。这似乎取决于桌面在做什么,但很难说。
public class TimeTest {
private static final int ONE_MILLION = 1000000;
private static final int HALF_MILLION = 499999;
public static void main(String[] args) {
long start = System.nanoTime();
long base = System.currentTimeMillis() - (start / ONE_MILLION);
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Don't care if we're interrupted
}
long now = System.nanoTime();
long drift = System.currentTimeMillis() - (now / ONE_MILLION) - base;
long interval = (now - start + HALF_MILLION) / ONE_MILLION;
System.out.println("Clock drift " + drift + " ms after " + interval
+ " ms = " + (drift * 1000 / interval) + " ms/s");
}
}
}
Thread.sleep() 时间的不准确以及中断应该与计时器漂移完全无关。
这两个 Java“系统”调用都旨在用作测量 - 一个用于测量挂钟时间的差异,另一个用于测量绝对间隔,因此当实时时钟未更改时,这些值应该以非常接近相同的速度变化,对吧?这是 Java 中的错误、弱点还是失败?操作系统或硬件中是否存在阻止 Java 更准确的东西?
我完全预计这些独立测量之间会有一些漂移和抖动 (**),但我预计每天的漂移不到一分钟。每秒 1 毫秒的漂移,如果单调,几乎是 90 秒!我观察到的最坏情况下的漂移可能是那个的十倍。每次我运行这个程序时,我都会在第一次测量时看到漂移。到目前为止,我运行程序的时间没有超过 30 分钟。
由于抖动,我希望在打印的值中看到一些小的随机性,但在程序的几乎所有运行中,我看到差异稳步增加,通常每秒增加 3 毫秒,增加几倍不止于此。
是否有任何版本的 Windows 具有类似于 Linux 的机制来调整系统时钟速度以缓慢地使时钟时钟与外部时钟源同步?这样的事情会影响两个计时器,还是只影响挂钟计时器?
(*) 我知道在某些架构上,System.nanoTime() 必然会使用与System.currentTimeMillis() 相同的机制。我还认为可以公平地假设任何现代 Windows 服务器都不是这样的硬件架构。这是一个糟糕的假设吗?
(**) 当然,System.currentTimeMillis() 的抖动通常比System.nanoTime() 大得多,因为它在大多数系统上的粒度不是 1 毫秒。
【问题讨论】:
-
GetSystemTimeAdjustment() 函数将返回有关调整是否处于活动状态及其参数设置的信息。
-
哈!你觉得你有问题?!我在一小时内看到了多达 0.01 的漂移,即在
System.nanoTime()增加了 3600 000 000 000 之后,只过去了 59 分半钟!
标签: java windows datetime time