本文來自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倍左右了,由於兩個值的參照不同,因此沒有可比性
推薦閱讀