System.nanoTime 是 Java 中获取高精度、单调递增时间戳的最佳选择,适合构建轻量低开销性能监控系统,但仅适用于单 JVM 内部时间差计算,不可用于超时判断、跨 JVM 比较或绝对时间表示。

System.nanoTime 是 Java 中获取高精度、单调递增时间戳的最佳选择,适合构建轻量、低开销的性能监控系统。它不受系统时钟调整影响,纳秒级精度(实际分辨率取决于底层 OS 和硬件),但不表示绝对时间,只适用于计算时间差。
用 nanoTime 实现方法耗时统计
核心思路是记录方法开始和结束时的 nanoTime 差值。避免直接打印或频繁日志,改用聚合或采样方式降低开销。
- 在方法入口调用 long start = System.nanoTime();
- 在方法出口计算耗时:long elapsed = System.nanoTime() - start;
- 建议将耗时转为微秒或毫秒展示(除以 1000 或 1_000_000),避免纳秒数值过大难读
- 不要用 nanoTime 做跨线程或长时间跨度的“定时”,它不保证跨 JVM 或重启后连续
构建可复用的监控计时器工具类
封装成 Timer 或 StopWatch 类,支持嵌套、命名、多阶段打点,提升可维护性。
- 定义一个 Timer 类,内部持有 startNs 字段和 tag 字符串
- 提供 start()、stop() 和 elapsedNanos() 方法,stop 后自动计算并清空状态
- 支持 elapsedMicros() 或 elapsedMillisRounded() 等便捷方法,减少重复转换
- 可选:添加 ThreadLocal 存储当前计时器,实现 AOP 或 Filter 中无侵入式埋点
集成到业务关键路径做采样监控
全量统计会拖慢性能,合理采样更实用。比如每 100 次请求记录 1 次耗时,或只监控 P95/P99 超时请求。
立即学习“Java免费学习笔记(深入)”;
- 用随机数决定是否开启计时:if (ThreadLocalRandom.current().nextInt(100) == 0)
- 把耗时数据存入环形缓冲区或滑动窗口(如使用 LongAdder + 时间分桶),避免锁和 GC 压力
- 定期导出统计指标:平均值、P50/P90/P99、最大值、调用次数,可通过 JMX 或 HTTP 端点暴露
- 注意:nanoTime 的值本身没有单位含义,不同机器间不可比,只用于单 JVM 内部相对测量
注意事项与常见陷阱
避开几个典型误用,才能让监控真实可靠。
- 别用 nanoTime 做超时判断:应使用 System.currentTimeMillis() 或 java.time.Instant 配合 ScheduledExecutorService
- 避免在循环内高频调用:nanoTime 本身很快,但反复调用 + 计算仍会累积开销,尤其在热点代码中
- 不要跨 JVM 比较 nanoTime 数值:每次 JVM 启动后基准偏移不同,且不同 CPU 核心可能有微小偏差
- 注意 JIT 优化影响:极短方法可能被内联或消除,导致测出 0 耗时;可加 volatile 变量读写或 Blackhole.consumeCPU() 干扰优化(仅测试用)



















