本文来自PerfMa技术社区:club.perfma.comlinux
PerfMa(笨马网络)官网:www.perfma.commacos
上周有同事问了我一个现象很诡异的问题,说JDK7和JDK8下的System.nanoTime()
输出彻底不同,并且差距还很是大,是否是两个版本里的实现不同,以前我也没注意过这个细节,以为很是奇怪,因而本身也在本地mac机器上立刻测试了一下,获得以下输出:网络
还真不同,因而我再到linux下跑了一把,发现两个版本下的值基本上差很少的,也就是主要是mac下的实现可能不同架构
因而我又调用System.currentTimeMillis()
,发现其输出结果和System.nanoTime()
也彻底不是1000000倍的比例分布式
另外System.nanoTime()
输出的究竟是什么东西,这个数字好奇怪函数
这三个小细节平时没有留意,好奇心做祟,因而立刻想一查究竟测试
再列下主要想理清楚的三个问题code
在mac下发现System.nanoTime()
在JDK7和JDK8下输出的值怎么彻底不同cdn
System.nanoTime()
的值很奇怪,到底是怎么算出来的blog
System.currentTimeMillis()
为什么不是System.nanoTime()
的1000000倍
在mac下,首先看JDK7的nanoTime实现
再来看JDK8下的实现
果真发现JDK8下多了一个__APPLE__宏下定义的实现,和JDK7及以前的版本的实现是不同的,不过其余BSD系统是同样的,只是macos有点不同,由于平时我们主要使用的环境仍是Linux为主,所以对于macos下具体异同就不作过多解释了,有兴趣的本身去研究一下。
在linux下JDK7和JDK8的实现都是同样的
而Linux::supports_monotonic_clock决定了走哪一个具体的分支
_clock_gettime的定义在
说白了,其实就是看librt.so.1或者librt.so中是否认义了clock_gettime函数,若是定义了,就直接调用这个函数来获取时间,注意下上面的传给clock_gettime的一个参数是CLOCK_MONOTONIC,至于这个参数的做用后面会说,这个函数在glibc中有定义
而对应的宏SYSDEP_GETTIME定义以下:
最终是调用的clock_gettime系统调用:
而咱们JVM里取纳秒数时传入的是CLOCK_MONOTONIC这个参数,所以会调用以下的方法
上面的wall_to_monotonic的tv_sec以及tv_nsec都是负数,在系统启动初始化的时候设置,记录了启动的时间
所以nanoTime其实算出来的是一个相对的时间,相对于系统启动的时候的时间
咱们其实能够写一个简单的例子从侧面来验证currentTimeMillis返回的究竟是什么值
你将看到输出结果会是两个同样的值,这说明了什么?咱们上一篇文章里已经提到了new Date(0).getTime()实际上是就是1970/01/01 08:00:00,而new Date().getTime()是返回的当前时间,两个日期一减,其实就是当前时间距离1970/01/01 08:00:00有多少毫秒,而System.currentTimeMillis()返回的正好是这个值,也就是说System.currentTimeMillis()就是返回的当前时间距离1970/01/01 08:00:00的毫秒数。
就实现上来讲,currentTimeMillis实际上是经过gettimeofday来实现的
至此应该你们也清楚了,为何currentTimeMillis返回的值并非nanoTime返回的值的1000000倍左右了,由于两个值的参照不同,因此没有可比性
推荐阅读