system.nanotime() 在 jvm 单进程生命周期内严格单调递增,基于操作系统单调时钟源(如 linux 的 clock_monotonic 或 windows 的 queryperformancecounter),仅支持同 jvm 内差值计算,不保证绝对时间精度或跨进程语义。

System.nanoTime() 的单调递增性,不是“尽量不跳、尽量不退”的宽松承诺,而是 JVM 在单个进程生命周期内严格保证的底层契约:只要 JVM 正常运行,该方法返回的值永远不会减小,也不会突变——它只持续累加。
单调性靠什么实现
它不读取系统时间(即“墙上时钟”),而是直接对接操作系统提供的单调时钟源:
- Linux 下通常调用
clock_gettime(CLOCK_MONOTONIC),该时钟从系统启动开始计数,不受 NTP 调整、闰秒、手动改时影响 - Windows 下一般使用
QueryPerformanceCounter,基于高精度硬件计数器(如 TSC)并做跨核同步校准 - JVM 启动时选定一个未公开的起始偏移点,之后所有返回值都是该起点后的纳秒累加量
单调性 ≠ 绝对精度
单调性保障的是顺序和方向,不是物理时间的完美复刻:
- 两次调用差值
end - start恒 ≥ 0,且精确反映真实经过时间(在硬件能力范围内) - 但单次返回值本身无意义:不能转成日期、不能跨 JVM 比较、重启后数值不连续
- 实际分辨率因平台而异(Linux 通常 1–15 纳秒,Windows 可能 10–15 毫秒),但无论分辨率如何,差值始终非负
哪些操作会破坏单调性效果
不是 API 本身失效,而是误用让单调优势无法兑现:
- 把
nanoTime()值存数据库、打印日志、传给其他进程——它一离开当前 JVM 就失去语义 - 在两次调用之间插入长时间阻塞(如 full GC、I/O 等待、锁竞争),虽不破坏单调性,但会让差值包含干扰项,不再是纯代码耗时
- 用
currentTimeMillis()和nanoTime()混合计算超时,导致逻辑受系统时钟扰动
典型正确用法锚点
所有可靠使用都围绕一个核心动作:紧邻调用、仅作差值、限定作用域:
- 超时控制:用一次
start = nanoTime(),循环中持续算nanoTime() - start,完全避开系统时间 - 性能测量:
start紧贴被测代码前,end紧贴其后,差值即为纳秒级耗时 - 倒计时/采样排序:依赖差值大小判断先后,天然杜绝时间倒流或相等异常











