-System.nanoTime() + System.nanoTime() 是否保证>= 0?

2022-09-04 02:16:34

嗨,大家好,我有一段代码,看起来像这样:

public class Test {
    public static void main(String args[]) {
        long a = System.currentTimeMillis(); // line 1
        long b = System.currentTimeMillis(); // line 2
        assert b - a >= 0;

        long y = System.nanoTime(); // line 5
        long z = System.nanoTime(); // line 6
    }
}

因此,IERS表示,下一个闰秒将立即发生在2012年6月3011:59.9之后。

我想知道我说是否正确,如果第1行在2012年6月30日11:59.9转1st 2012年7月100:00.0之后以0.9秒运行,

第 2 行在第 1 行之后以 0.1 秒的速度运行,

的结果可能是负面的 ?(-900 毫秒)b - a

如果是这种情况,如果第 5 行在 2012 年 6 月 30 11:59.9 转 2012 年 7 月 1 日 00:00.0 之后以 0.9 秒的速度运行,

第 6 行在第 5 行之后以 0.1 秒的速度运行,

的结果可能是负面的 ?(-900,000,000 纳秒?z - y


答案 1

System.nanoTime 应该是单调递增的 -- 如果你有两个调用它, 和 , 和 happen-before ,那么 .但在实践中,你实际上可以观察到“倒退”。ABABA <= BnanoTime

nanoTime由 CPU 上的内部计数器确定,其启动时间基本上是任意的(这就是为什么它不能用于确定挂钟时间的原因)。这可能会导致多核环境中出现问题,因为一个内核的内部计时器可能具有与另一个内核不同的起点。Hotspot试图弥补这一点,但它并不总是成功,所以你实际上可以看到在某些情况下滴答作响。nanoTime

最近在并发利益邮件列表上有一个关于这个问题的讨论。请特别查看这封电子邮件,其中链接到此错误报告,以及这封电子邮件,其中讨论了解决方法(这似乎不起作用,尽管我不确定为什么)。错误报告有相当多的细节。


答案 2

如果我说得对吗,如果第1行在2012年6月30日11:59.9转2012年7月1日00:00.0之后以0.9秒运行,

如果时钟未调整,则 0.9 秒后30th June 2012 11:59.91st July 2012 00:00.8

b - a 的结果将为负数 ?

currentTimeMillis() 是自 1970 年以来以毫秒为单位的时间。它不会在一天开始时重置。或您一生中的任何时候。

z - y 的结果是否为负数 ?

nanoTime() 也不是自一天开始以来的时间。在许多JVM/操作系统上,它是自上次重置CPU以来的纳秒数。


并非所有操作系统都提供相同的分辨率。例如,RHEL/Centos 5.x 仅提供微秒分辨率。这意味着您可以连续多次调用,并给出相同的值(到微秒)

long a = System.currentTimeMillis(); // line 1
long b = System.currentTimeMillis(); // line 2
assert b - a >= 0;

每当通过向后转动时间来纠正时间时,这都会倒退。例如,通过NTP。

long y = System.nanoTime(); // line 5
long z = System.nanoTime(); // line 6

这将在具有多个套接字的系统上倒退,这些套接字无法校正不同套接字中时间戳计数器的差异。例如,如果您使用的是Windows XP并且有两个套接字,则当它在套接字之间切换线程时,您可以看到差异向前或向后跳跃4,000,000。


推荐