最近查了个关于 System.nanoTime()
的问题,起因是业务里面将 System.nanoTime()
返回的数值作为了业务中的唯一值,最后发现了值相同的数据,询问编写这块代码的同事,同事反馈说当时编写的时候以为 System.nanoTime()
的精度很高,不会出现重复的数据。但是从现象来看,出现了重复的数据。
我们可以用一段简单的代码复现该问题:
1 | public class Test { |
使用 javac Test.java
编译该类,再使用 java Test
执行以上代码,在 4 核的 Linux 系统上打印了不少 nanoTime not unique
。可知,出现了重复的数据。
System.nanoTime()
对应的 Java 源码位于 System.java:
1 | /** |
其中特意提到:
This method provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes) - no guarantees are made except that the resolution is at least as good as that of
currentTimeMillis()
.
即值更改的频率不保证能够达到纳秒解析度。关于这一点,在 Nanotrusting the Nanotime 中也有提及:
nanoTime
is not nanosecond resolution; at best, you can hope for 30 ns resolution, and it varies wildly between platforms
System.nanoTime()
方法在 Linux 下的源码实现位于 os_linux.cpp:
1 | jlong os::javaTimeNanos() { |
可知,当 Linux 支持单调时钟时,调用的为 clock_gettime
方法,且调用时传入的参数为 CLOCK_MONOTONIC
。当不支持单调时钟时,调用的为 gettimeofday
方法。我们使用如下的程序来 debug 下 native 方法:
1 | public class TestNative { |
对 TestNative
使用 gdb debug:
1 | (gdb) break os::javaTimeNanos |
确认在我们的生产环境中,调用的为 clock_gettime
方法,关于参数 CLOCK_MONOTONIC
,其文档位于 clock_gettime(3) - Linux manual page:
A nonsettable system-wide clock that represents monotonic time since—as described by POSIX—“some unspecified point in the past”. On Linux, that point corresponds to the number of seconds that the system has been running since it was booted.
The
CLOCK_MONOTONIC
clock is not affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP. This clock does not count time that the system is suspended. AllCLOCK_MONOTONIC
variants guarantee that the time returned by consecutive calls will not go backwards, but successive calls may—depending on the architecture—return identical (not-increased) time values.
即持续的调用可能返回相同的值(取决于架构实现)。
Reference
Is System.nanoTime() guaranteed to return unique values? - Stack Overflow
Is the system nanoTime unique? - Quora
Can I trust that System.nanoTime() will return different value each invocation? - Stack Overflow
How to debug a native function in Java - Quora
gdb tutorial