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

System.nanoTime() 是 Java 中唯一适合高精度性能测量的时间 API,它不提供“现在几点”,只回答“这段代码跑了多久”,而且尺子刻得够细——纳秒级分辨率、单调不跳变、无系统时钟干扰。
为什么 nanoTime 比 currentTimeMillis 更可靠
currentTimeMillis() 返回的是自 1970 年起的毫秒数,本质是系统墙钟。它受 NTP 校时、手动改时间、闰秒等影响,压测中可能出现负耗时或统计断层。nanoTime() 则基于内核单调时钟(如 Linux 的 CLOCK_MONOTONIC 或 Windows 的 QueryPerformanceCounter),起点虽“任意”(通常是 JVM 启动时刻),但全程稳定递增,差值就是真实经过时间。
- 精度差异:nanoTime 实际分辨率通常为 10–100 纳秒;currentTimeMillis 在 Windows 下可能低至 15.6 毫秒
- 适用场景不同:前者专为耗时测量设计;后者用于日志时间戳、定时任务触发等需绝对时间的场合
- 跨平台一致性更强:Linux/macOS/Windows 上 nanoTime 行为统一;currentTimeMillis 在各系统上精度波动大
正确写法:两次调用 + 差值计算
核心就一句话:只用差值,不用单值。System.nanoTime() 返回的 long 数字本身没有物理意义,就像跑步计时器上的“00:00:00”不代表凌晨零点,只是起点标记。
- 在业务逻辑前立即记录:long start = System.nanoTime();
- 在业务逻辑后立即记录:long end = System.nanoTime();
- 计算耗时:long ns = end - start;(单位:纳秒)
- 避免包裹无关操作:不要把日志打印、对象创建、锁等待等非目标逻辑包进去
单位转换要注意除法类型
纳秒转微秒或毫秒时,整数除法会截断小数,导致系统性低估。例如 1999 纳秒 ÷ 1000 = 1 微秒,实际丢失了近一半精度。
立即学习“Java免费学习笔记(深入)”;
- 要保留小数:用 durationNs / 1000.0(得 double,单位微秒)或 durationNs / 1_000_000.0(单位毫秒)
- 做阈值判断可用整数截断:durationNs / 1000 >= 100 表示是否超 100 微秒
- 统计平均值或绘图务必用浮点运算,避免多次整除放大误差
实战中容易踩的坑
即使调用方式正确,环境干扰仍会让结果失真。关键不是“能不能测”,而是“测到的到底是什么”。
- JIT 预热不足:首次运行含类加载和编译开销,建议空跑 10000 次再开始采集
- GC 干扰:Full GC 可暂停线程数百毫秒,此时 nanoTime 仍在走,但业务没执行——应结合 GC 日志交叉分析
- 测量粒度太细:测单条 i++ 这类极短操作时,nanoTime 自身调用开销(约 10–50 纳秒)已接近被测对象,应批量执行后均摊
- 跨线程误用:start 和 end 必须在同一线程同一路径,否则可能被调度中断、上下文切换污染


















