System.nanoTime() 底层解析

在Random类的构造函数实现中存在System.nanoTime()的调用:

public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

在System类中声明:

public static native long nanoTime();

这个方法是个调用系统实现的native方法,由C语言实现,IDEA无法查看。

官方文档:
返回正在运行的Java虚拟机的高分辨率时间源的当前值,以纳秒为单位。
此方法只能用于测量经过的时间,并且与系统或挂钟时间的任何其他概念无关。返回的值表示纳秒,因为某些固定的任意原点时间可能在将来,因此值可能为负。
在Java虚拟机的实例中,所有对此方法的调用都使用相同的原点;其他虚拟机实例可能使用不同的来源。
此方法提供纳秒级精度,但不一定是纳秒级分辨率(即,值的变化频率) 。
除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证。

连续调用的差异超过大约292年(2^63纳秒)将无法正确计算由于数值溢出而导致的经过时间。
只有在计算在Java虚拟机的同一实例中获得的两个此类值之间的差异时,此方法返回的值才有意义。

例如,要测量某些代码执行所需的时间:

long startTime = System.nanoTime();
/* 省略的测量代码段... */
long estimatedTime = System.nanoTime() - startTime;
long time1 = System.nanoTime(); 
/* 省略的测量代码段... */
long time2 = System.nanoTime();

注意:这里应该使用 t1 - t0 < 0,而不是 t1 < t0,因为数字溢出的可能性.

慎用System.nanoTime() :

  • System.nanoTime()是基于cpu核心的时钟周期来计时,它的开始时间是不确定的。
  • 在多核处理器上,由于每个核心的开始时间不确定,同一段代码可能被不同核调用而产生完全不同的结果。
  • 详情:System.html#nanoTime()

准确的说,System.nanoTime()是使用QueryPerformanceCounter/ queryperformancfrequency API实现的,QPC使用的默认机制是由硬件抽象层(HAL)决定的,这个默认值不仅在硬件上,而且在操作系统版本上都会改变。例如,Windows XP Service Pack 2更改了使用电源管理计时器(PMTimer)而不是处理器时间戳计数器(TSC),因为在SMP系统中,TSC没有在不同的处理器上同步。而且由于它的频率会根据电源管理设置而变化(以及它与运行时间的关系)。

现在在多核系统中,可能在测量time1之后,线程被调度到不同的处理器,该处理器的计数器小于前一个CPU的计数器。因此,我们可以得到time2的值小于time1。因此,我们将得到一个负数的时间花费。每个CPU将保持一个不同的计数器,因为它是打开的。与第一个CPU相比,第二个CPU上的这个计数器可以更低。由于线程在获得time1后可以被操作系统调度到第二个CPU,所以timeespent的值可能不正确,甚至为负值。

参考:https://stackoverflow.com/questions/510462/is-system-nanotime-completely-useless

这个问答里面说明,在windows系统上这曾经是一个问题,但是现在它被修复了,因此现在使用System.nanoTime()很安全(至少在同一个虚拟机内)。

还有一个值得关注的问题是,System.nanoTime()的性能不如System.currentTimeMillis(),这是因为

System.currentTimeMillis()是使用GetSystemTimeAsFileTime方法实现的,该方法基本上只读取Windows维护的低分辨率时间值。根据所报告的信息,读取这个全局变量自然很快,大约6个周期。
System.nanoTime()使用实现所述QueryPerformanceCounter/ QueryPerformanceFrequency API(如果可用的话,否则它返回currentTimeMillis*10^6)。
QueryPerformanceCounter(QPC)在这取决于它的运行在硬件上不同的方式实现。通常,其使用两可编程间隔计时器(PIT)或ACPI电源管理计时器(PMT),或CPU级别的时间戳计数器(TSC)访问PIT/ PMT需要执行慢速I / O端口指令,因此QPC的执行时间大约为几微秒。100个时钟周期的顺序(从芯片读取TSC并将其转换为基于工作频率的时间值)。

但是即使性能较慢,System.nanoTime()仍然能够提供更精确的计时,因为自身的精度足够高,即使单次运行需要耗费额外的时间,也无足轻重。

总结

总的来说,System.nanoTime()方法主要的应用还是集中在高精度计时上,当然,拿来做随机种子也是一个重要应用,但是Random类我们不需要去实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Whitemeen太白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值