System.nanoTime()的返回值只和進程已運行的時間有關, 不受調系統時間影響.
以前測試netty中的一個時間輪工具類(HasedTimeWheel)發現它不支持調系統時間, 比如一個任務是6點執行, 提交到時間輪后, 把系統時間調到7點,. 任務不會立即執行, 但是看HasedTimeWheel的代碼感覺在設計上是支持調時間的(即調到7點后任務應該立即執行), 一頓測試后發現此類以System.nanoTime()作為"當前時間", 要想支持調時間, 只需要把System.nanoTime()替換成System.currentTimeMillis()(相關時間單位也要改).
System.nanoTime()的返回值要用相減是否大於0來判斷調用的先后順序, 但不能用>或<來判斷.
System.nanoTime()返回的數值實際是64位無符號數, 隨着進程運行時間增長, 溢出后再從0開始, 賦值給long類型相當於當做補碼數(有符號數)使用, 其值循環規律如下:
最小負數 -> 0 -> 最大正數 -> 最小負數 -> ...
假設有兩次先后順序未知的調用, 且兩次調用時間間隔小於2^63ns (約200+year)
long t1 = System.nanoTime();
long t2 = System.nanoTime();
如果t1和t2都是正數或t1和t2都是負數, 則t1和t2的差不會超過2^63, 它們相減不會溢出, t1>t2 <=> t1-t2>0, 且較大的數一定是后一次調用返回的, 所以用相減比較和><運算符比較都可以 ;
如果t1和t2一正一負, 設t2是正數, 對比它們作為無符號數時的值, 可以知道負數t1才是后一次調用返回的, 所以由t2>t1得出t2是后一次調用是錯誤的. 另外我們假設了兩次調用間隔小於2^63, t2-t1的值一定大於2^63 (放在long里面是負數), 所以有t2-t1<0, 此時用相減來判斷仍然是正確的.
System.currentTimeMillis()返回的是自1970年到現在的毫秒數,但是System.nanoTime()輸出可能讓我們丈二和尚摸不着頭腦
根據納秒方法的注釋:
Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds.
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative). The same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin.
翻譯一下就是:返回當前JVM的高精度時間。該方法只能用來測量時段而和系統時間無關。它的返回值是從某個固定但隨意的時間點開始的(可能是未來的某個時間)。不同的JVM使用的起點可能不同。
這樣有點恐怖的是我們相同的代碼在不同機器運行導致結果可能不同。所以它很少用來計算,通常都是測量先后順序和時間段