system.nanotime()是java中唯一适合高精度性能测量的时间api,基于内核单调时钟,纳秒级分辨率、单调递增、不受系统时钟调整影响,仅适用于耗时差值计算,不可用于绝对时间。

System.nanoTime() 是 Java 中获取单调时间戳的标准方式,它返回的是从某个未指定起点开始的纳秒级计时值,不反映真实世界时间(如 1970 年至今),但保证严格单调递增、不受系统时钟调整(如 NTP 校正、手动改时间)影响。
为什么 nanoTime 是单调的?
它底层通常基于高精度、不可逆的硬件计时器(如 x86 上的 TSC,ARM 上的 CNTPCT_EL0),操作系统将其封装为“单调时钟”(monotonic clock)。这意味着:
- 两次调用结果满足:若 t2 在 t1 之后发生,则 nanoTime(t2) ≥ nanoTime(t1)
- 即使系统时间被向前或向后修改(比如管理员执行
date -s或 NTP 跳变),nanoTime() 不会回跳或突变 - 它不保证绝对精度(可能有几纳秒到微秒级误差),但差值(duration)非常可靠
怎么正确使用 nanoTime 获取时间间隔?
它只适合测时长,不能直接当“当前时间”用。典型模式是记录起止值再相减:
long start = System.nanoTime(); doSomeWork(); long end = System.nanoTime(); long durationNs = end - start; // 纳秒级耗时,安全、单调、精确 long durationMs = TimeUnit.NANOSECONDS.toMillis(durationNs); // 转毫秒(注意四舍五入)
⚠️ 注意:不能拿 nanoTime 值和 System.currentTimeMillis() 比较,二者起点和语义完全不同。
常见误区与注意事项
- 不要用作时间戳存储或日志时间:因为它没有可读性,也无法转换成北京时间
- 避免长时间跨度比较:虽然理论上单调,但 long 最大值约 9.2E18 纳秒(≈292 年),一般不会溢出;但若程序运行数十年且频繁累加,仍需谨慎
- JVM 启动后首次调用可能稍慢:因需初始化底层计时器,但后续调用极快(通常几十纳秒)
- 跨 CPU 核心可能有微小偏差:在某些老硬件或虚拟化环境中,不同核心的 TSC 可能不同步(现代 JVM 和 OS 通常已做校准)
替代方案对比
若你需要“既单调又带时区”的时间戳,应组合使用:
- 用 System.nanoTime() 测量性能、计算延迟、实现超时逻辑
- 用 System.currentTimeMillis() 或 Instant.now() 记录事件发生时刻(注意:它们可能跳变)
- 高精度+单调+可读时间?考虑 Clock.tickNanos(Clock.systemUTC(), Duration.ofNanos(1))(Java 9+),但本质仍是包装 nanoTime,不改变其无日期特性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











