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");
}
}
}
< p > Thread.sleep()
的时间不准确,以及中断,应该与计时器漂移完全无关。
这两个Java "System"调用旨在用作测量 - 一个用于测量壁钟时间的差异,另一个用于测量绝对间隔,因此当实时时钟未被更改时,这些值应该以非常接近相同的速度变化,对吗?这是Java中的错误、弱点还是失败?有没有什么OS或硬件阻止Java更加准确?
我完全期望这些独立测量之间存在一定的漂移和抖动(**),但我预计每天的漂移应该少于一分钟。如果单调地漂移1毫秒/秒,那么将近90秒!我观察到的最坏情况漂移可能是那个的十倍。每次运行此程序时,我都会看到第一个测量的漂移。到目前为止,我还没有运行程序超过30分钟。
我希望看到打印值中的一些小随机性,由于抖动,但在几乎所有运行程序的情况下,我看到差异的稳定增加,通常每秒增加3毫秒,有时更多。
任何Windows版本是否具有类似于Linux的机制,调整系统时钟速度,缓慢将日历时钟与外部时钟源同步?这种事情会影响两个计时器还是只有壁钟计时器?
(*) 我了解到,在某些体系结构上,System.nanoTime()
必须使用与 System.currentTimeMillis()
相同的机制。我也相信可以假设任何现代Windows服务器都不是这样的硬件体系结构。这是一个错误的假设吗?
(**) 当然,System.currentTimeMillis()
在大多数系统上其粒度不是1毫秒,因此通常具有更大的抖动比 System.nanoTime()
。
System.nanoTime()
增加了3600 000 000 000后,只过去了59分半钟! - Feuermurmel