System.nanoTime()是Java测量执行耗时的唯一可靠选择,因其基于操作系统单调时钟,不受系统时间调整影响,仅适用于计算差值,需避免单次测量、跨线程比较及误作业务时间戳。

System.nanoTime() 是 Java 中测量代码执行耗时的**事实标准**,不是因为它返回“纳秒”就天然精确,而是因为它专为“经过时间”(elapsed time)设计:单调、高分辨率、不受系统时钟干扰。
为什么它是唯一可靠的选择
它底层调用操作系统级单调时钟(如 Linux 的 CLOCK_MONOTONIC 或 Windows 的 QueryPerformanceCounter),起点任意、持续递增。哪怕你手动把系统时间拨快或拨慢,甚至 NTP 同步跳变,nanoTime 的差值依然稳定为正——这对性能测量至关重要。而 currentTimeMillis() 依赖墙钟,可能倒退、跳跃、卡顿,毫秒级分辨率在微秒级场景下直接失效。
怎么用才真正有效
- 只做差值:start = System.nanoTime(); doWork(); end = System.nanoTime(); elapsedNs = end - start —— 绝对值毫无意义,也不能转成日期或存库
- 单位换算要小心:除以 1_000_000.0 得毫秒(double),除以 1000.0 得微秒;整数除法(/1000)会截断,丢失精度
- 单次测量没价值:JIT 编译、CPU 频率切换、线程抢占都会污染结果;至少预热 10k 次 + 正式采样 100 轮以上,再取中位数或截尾均值
- 避免自身开销干扰:nanoTime() 调用本身约 20–50 纳秒,测短于 100 纳秒的操作时,应批量执行后均摊,而非逐次打点
哪些坑必须避开
跨线程直接比 nanoTime 值不可靠——不同 CPU 核心的 TSC 可能未完全同步;超长间隔(如几小时以上)虽不溢出,但休眠、电源管理会导致漂移;更关键的是,它不能替代业务时间戳——日志打点、超时控制、订单生成一律该用 currentTimeMillis()。
生产环境落地要点
别只记一个数字。用 ThreadLocal

















