System.nanoTime()的精度与准确度

System.nanoTime()的文档说明如下(强调我的)。

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。 返回的值表示纳秒,因为某些固定但是任意时间(可能在将来,因此值可能为负)。 该方法提供纳秒精度,但不一定是纳秒精度。 不保证值的变化频率。

在我看来,这可以用两种不同的方式解释:

  1. 上面粗体的句子指的是个人返回值。 然后,从数值意义上理解精度和准确度。 也就是说,精确度是指有效数字的位数 – 截断的位置,精确度是指数字是否正确(如前面的答案中所述,’精确’和’准确度’之间有什么区别? )

  2. 上面粗体的句子指的是方法本身的能力。 然后,精确度和准确度将被理解为飞镖类比( http://en.wikipedia.org/wiki/Precision_vs._accuracy#Accuracy_versus_precision:_the_target_analogy )。 因此,低精度,高精度=>错误的值被高精度地反复击中:想象物理时间静止,nanoTime()的连续调用返回相同的数值,但是它与实际经过的时间相比有所不同。参考时间通过一些常数偏移。

哪种解释是正确的? 我的观点是,解释2意味着使用nanoTime()(通过减去两个返回值)测量时间将是正确的纳秒(因为测量中的常数误差/偏移将被消除),而解释1将不会不能保证测量之间的一致性,因此不一定意味着高精度的时间差测量。


2013年 4月15日更新: System.nanoTime()的Java 7文档已更新,以解决与先前措辞可能混淆的问题。

返回正在运行的Java虚拟机的高分辨率时间源的当前值,以纳秒为单位。

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。 返回的值表示纳秒,因为某些固定但任意的原始时间(可能在将来,因此值可能为负)。 在Java虚拟机的实例中,此方法的所有调用都使用相同的原点; 其他虚拟机实例可能使用不同的来源。

此方法提供纳秒级精度,但不一定是纳秒级分辨率(即,值的变化频率) – 除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证。

由于数值溢出,跨越大于约292年(2 63纳秒)的连续调用的差异将无法正确计算经过的时间。

仅当计算在Java虚拟机的同一实例中获得的两个此类值之间的差异时,此方法返回的值才有意义。

第一种解释是正确的。 在大多数系统中,三个最低有效数字将始终为零。 这实际上提供了微秒精度,但是以纳秒的固定精度水平报告。

事实上,现在我再次看一遍,你的第二种解释也是对正在发生的事情的有效描述,甚至更多。 想象冻结时间,报告将始终是相同的错误纳秒数,但如果理解为整数微秒,则更正。

在Clojure命令行中,我得到:

 user=> (- (System/nanoTime) (System/nanoTime)) 0 user=> (- (System/nanoTime) (System/nanoTime)) 0 user=> (- (System/nanoTime) (System/nanoTime)) -641 user=> (- (System/nanoTime) (System/nanoTime)) 0 user=> (- (System/nanoTime) (System/nanoTime)) -642 user=> (- (System/nanoTime) (System/nanoTime)) -641 user=> (- (System/nanoTime) (System/nanoTime)) -641 

从本质nanoTimenanoTime不会每纳秒更新一次,这与人们对其精确度的直观预期相反。 在Windows系统中,它使用了QueryPerformanceCounter API(根据本文 ),实际上它似乎提供了大约640 ns的分辨率 (在我的系统中!)。

请注意, nanoTime本身不具备任何精度 ,因为它的绝对值是任意的。 只有连续的nanoTime调用之间的差异才有意义。 该差异的(in)准确度在1微秒的范围内。

System.currentTimeMillis()System.nanoTime()之间差异的一个非常有趣的特性是System.nanoTime()不会随挂钟而改变。 我在具有大量时间漂移的Windows虚拟机上运行代码。 每当NTP纠正该漂移时, System.currentTimeMillis()可以每次跳回或向前跳1-2秒,从而使准确的时间戳无意义。 (Windows 2003,2008 VPS版本)

但是, System.nanoTime()不会受到更改挂钟时间的影响,因此您可以通过NTP检索时间并根据System.nanoTime()应用更正,因为最后检查了NTP,并且您的准确时间远远超过在逆壁时钟条件下的System.currentTimeMillis()

这当然是违反直觉的,但有用的知识

如果像我这样的人来这里一次又一次地读这个问题仍然有点理解它,这里有一个更简单(我希望)的解释。

Precision是指您保留的位数。 每一个:

 long start = System.nanoTime(); long end = System.nanoTime(); 

将是一个精确的数字(很多数字)。

由于accuracy与某些东西相比较 ,因此单独调用System.nanoTime是没有意义的,因为它的值非常随意,并且不依赖于我们可以测量的东西。 区分它的准确性的唯一方法是对它进行两次不同的调用,因此:

  long howMuch = end - start; 

不会有纳秒精度。 事实上在我的机器上,差异是0.2 – 0.3微秒。