system.nanotime()的单调性指其在单个jvm内严格递增、不回拨不突跳且不受系统时钟调整影响,因它基于硬件高精度计数器(如linux的clock_monotonic或x86的tsc),仅做累加不读墙钟。

System.nanoTime() 的单调性,核心就一句话:它不关心“现在几点”,只保证“时间只往前走”。它的值在单个 JVM 进程内严格递增,不会回拨、不会突跳,也不受系统时间修改影响。
为什么能保证单调?
它不读取系统时钟(wall-clock),而是直接对接底层硬件高精度计时器:
- 在 Linux 上通常调用
clock_gettime(CLOCK_MONOTONIC),该时钟从系统启动起累加,不受 NTP 校准、手动改时、闰秒干扰 - 在 x86 CPU 上可能基于 TSC(Time Stamp Counter),由硬件自动递增,JVM 启动时做一次校准并固定原点
- JVM 内部不做任何时间调整逻辑,只做累加——起点是任意的(可能是 JVM 启动时刻,甚至设在未来),但一旦选定就不再变更
单调性 ≠ 绝对精度
单调性解决的是“顺序和方向”问题,不是“刻度有多细”:
- 差值为 0 很常见:底层分辨率有限(如某些 Windows 环境下约 15ms)、JIT 优化掉空操作、或待测代码本身快于计时器最小分辨间隔
- 返回值可能为负:起点设在未来,或 long 溢出(约 292 年后),但这完全不影响
t2 - t1的正确性 - 跨核/虚拟化环境可能有微小漂移:多 CPU 核心 TSC 不完全同步,容器中启用 CPU quota 也可能导致非线性计时偏差
单调性的真正价值在差值计算
它的设计目的从来不是输出一个“时间戳”,而是支撑可靠的时间间隔测量:
- 超时判断:用一个
start = nanoTime()锚定起点,后续所有nanoTime() - start都是真实经过纳秒数,哪怕中间系统被回拨 1 小时也毫无影响 - 性能压测:多次调用差值可比,因为差值消除了起点偏移和系统扰动,只反映真实执行耗时
- 环形缓冲区采样:时间戳必须严格递增,否则排序、去重、滑动窗口逻辑会出错
常见误用:把单调性当万能钥匙
单调性只在特定约束下生效,踩错就失效:
- 禁止存储或传输 nanoTime() 值:它跨线程、跨 JVM、跨重启都不可比,打印日志、写数据库、序列化到 Kafka 都属于误用
- 避免长间隔单次测量:中间若发生 GC、线程挂起、锁竞争,测得的“耗时”实际包含停顿,不是纯代码执行时间
- 不能和 currentTimeMillis() 混用:两者基准不同、单位不同、语义冲突,相减或转换毫无意义










