关于System.nanoTime()的一点理解

编程入门 行业动态 更新时间:2024-10-26 14:39:03

事情起源

最近在研究Java中的Random实现的时候,发现Random的种子有用到System.nanoTime()

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

以前在学Java的时候,就听别人说过,Java中的随机数都是伪随机数,是通过随机种子通过复杂的计算得到的,而Java中的种子和时间有关,但是为什么用的是这个方法呢?搜索一番之后得出结论,原来是因为,现在计算机的运行速度很快,如果使用常规时间去做种子的话,有可能出现生成的随机数差别很小甚至完全一样的情况。而nanotime()这个方法,返回的是纳秒级精度的时间,以此作为种子更能保证生成数字的随机性。

出于好(无)奇(聊),我便研究了下这个方法。

首先是源码

在IDE中点进方法源码,发现这个方法是个调用系统实现的native方法,具体实现源码是看不到的

public static native long nanoTime();

没了源码只能看看文档了,文档中对这个方法的介绍如下(文档来自javadoc,通过谷歌翻译为中文)

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

此方法只能用于测量经过的时间,并且与系统或挂钟时间的任何其他概念无关。返回的值表示纳秒,因为某些固定的任意原点时间 (可能在将来,因此值可能为负)。

在Java虚拟机的实例中,所有对此方法的调用都使用相同的原点;其他虚拟机实例可能使用不同的来源。 此方法提供纳秒级精度,但不一定是纳秒级分辨率(即,值的变化频率) - 除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证。

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

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

long startTime = System.nanoTime(); // ...正在测量的代码...... long estimatedTime = System.nanoTime() -  startTime; 比较两个nanoTime值 long t0 = System.nanoTime(); ... long t1 = System.nanoTime();

一个应该使用t1 - t0 <0,而不是t1 <t0,因为数字溢出的可能性.

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

从以下版本开始:1.5

嗯...翻译有点感人,不过大概能看懂是干嘛的。

返回正在运行的Java虚拟机的高分辨率时间源的当前值,以纳秒为单位。
此方法只能用于测量经过的时间,并且与系统或挂钟时间的任何其他概念无关。

System.nanoTime()是基于cpu核心的时钟周期来计时,它的开始时间是不确定的,网上有篇文章说是更加cpu核心的启动时间开始计算的,不过具体的我也不能确定,只知道是与cpu有关就是了。

从文档来看,System.nanoTime()这个方法一个比较显著的应用是用来提供高精度的计时,不过两次调用的间隔不能超过2^63纳秒(大概292年),目前来看,应该暂时没有人有这么长的需求...

我在网上看到有人说,使用System.nanoTime()去计时会有隐患,比如在多核处理器上运行,不同的调用可能获取的是不同的核心的时间,而多核处理器不同核心的启动时间可能不完全一致,这样会造成计时错误,但是在Stack Overflow上我找到了一个问答:

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()仍然能够提供更精确的计时,因为自身的精度足够高,即使单次运行需要耗费额外的几纳秒(也许),也无足轻重。

总结

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

说到Random,好像我原来要研究的是Random来着,算了,不管了,下次有空再说吧,这篇文章就到这里结束了,感谢阅读(然而好像并没有什么干货)。

更多推荐

关于System.nanoTime()的一点理解

本文发布于:2023-06-14 09:06:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1459545.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:System   nanoTime

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!