在Windows操作系统上,Java时钟的准确度为15-16毫秒。

4
最近Windows上的时钟精度似乎有所改变。我记得自Windows 7以来很准确(1毫秒分辨率),现在时间会以15至16毫秒的步长跳动。我因一些(尽管写得不好)单元测试失败而注意到了这一点(测试检查写记录和读记录之间的某些时间间隔)。
这影响以下实现:
- System.currentTimeMillis() - LocalTime.now() - LocalDateTime.now() - ZonedDateTime.now()
我知道要使用System.nanoTime()差值来测量经过的时间,但我仍然想知道是否错过了将时钟分辨率改回15-16毫秒的更改。
环境:
- Windows 10版本1709 - JRE/JDK 1.8.0_171-b11(64位)
是否有人也注意到了这一点?这种分辨率更改的原因是什么?
编辑: 检查此行为的测试代码(请参见输出:时间更改和更改之前的样本数)
@Test
public void testCurrentTimeMillis() {
    test(() -> System.currentTimeMillis());
}

@Test
public void testNanoTime() {
    test(() -> System.nanoTime());
}

@Test
public void testLocalTime() {
    test(() -> LocalTime.now());
}

@Test
public void testLocalDateTime() {
    test(() -> LocalDateTime.now());
}

@Test
public void testZonedDateTime() {
    test(() -> ZonedDateTime.now());
}

private <T> void test(Supplier<T> timeSupplier) {

    int samples = 20;
    String lastTimeString = null;
    int count = 0;
    while (samples > 0) {

        count++;
        String timeString = timeSupplier.get().toString();
        if (!timeString.equals(lastTimeString)) {
            System.out.println(timeString + " (" + count + ")");
            lastTimeString = timeString;
            count = 0;
            samples--;
        }
    }
}

@ShanuGupta:不,它关闭了(在“侧向加载应用程序”上)。 - Peter Walser
你能打开并再次检查一下吗?你可能需要重新启动系统。 - Shanu Gupta
可能是Java中的计时器精度问题的重复问题。 - Ole V.V.
@OleV.V. 另一个问题可以追溯到2009年,当时在32位Windows平台上这种不准确性很常见。我的情况是最近的64位Windows平台,问题再次出现。 - Peter Walser
我已经搜索了一些,但都没有结果。你可能做得更好。无论如何,如果我没记错的话,最近我读到这是一个Windows问题(在2018年仍然存在),因此不是仅通过Java就能解决的。有一些技巧可以说服Windows提供更好的分辨率,但它们会消耗大量电力,所以如果可能的话,应该谨慎使用它们。还有一个JDK bug正在处理中,旨在在Windows上实现更好的准确性。免责声明:正如我所说,这一切都来自脆弱的记忆。 - Ole V.V.
显示剩余3条评论
1个回答

1
为了获得具有最佳准确性的本地时间,不考虑平台因素,我想出了一种解决方案,该方案基于当前时间(测量增加时间)作为锚点,并且基于 System.nanoTime() 偏移量进行偏移。
优点:
  • 当前时间不依赖于平台的精度
  • 高准确性 (纳秒)
  • 可移植性 (因为java.time对象可以实际上承载纳秒精度).
代码(可以适应为服务于LocalTimeLocalDateTime):
/**
 * Exact zoned date/time, compensates for the 15-16ms leaps 
 * of milliseconds time on some Java platforms.
 */
public final class ExactZonedDateTime {

    private static ZonedDateTime anchor;
    private static long anchorNanos;

    static {
        ZonedDateTime last = ZonedDateTime.now();
        while (((anchor = ZonedDateTime.now()).equals(last))) {
            anchorNanos = System.nanoTime();
        }
    }

    private ExactZonedDateTime() {
    }

    public static ZonedDateTime now() {
        return anchor.plusNanos(System.nanoTime() - anchorNanos);
    }
}

后续调用:

2018年4月26日12:51:02.293079632+02:00[欧洲/苏黎世] 2018年4月26日12:51:02.293524865+02:00[欧洲/苏黎世] 2018年4月26日12:51:02.293598126+02:00[欧洲/苏黎世] 2018年4月26日12:51:02.293660770+02:00[欧洲/苏黎世] 2018年4月26日12:51:02.293725538+02:00[欧洲/苏黎世]


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