
直接用 System.nanoTime() 测量微秒级耗时,关键不是“转换成微秒”,而是**正确采样差值并避免常见陷阱**。Java 的 nanoTime() 返回的是纳秒(nanosecond)为单位的单调时钟值,精度高、不受系统时间调整影响,适合性能测量;但它的实际分辨率取决于底层 OS 和硬件(通常在几十到几百纳秒),所以“微秒级”是合理目标,但别指望稳定到 1 微秒。
正确获取纳秒差值并转为微秒
只需两行代码:起始采样 + 结束采样 → 相减 → 除以 1000:
long start = System.nanoTime(); // ... 你要测的代码块(务必短小、无 I/O、无锁争用) long end = System.nanoTime(); long microseconds = (end - start) / 1000; // 向下取整,单位:微秒
注意:不要用 TimeUnit.NANOSECONDS.toMicros(...) —— 它内部也是除以 1000,但多一层方法调用开销,对微秒级测量有干扰。
赋值给性能监控变量的推荐方式
监控变量通常是 long 类型(如 Micrometer 的 Timer.Sample、Dropwizard 的 Timer.Context,或自定义的原子计数器)。直接赋值前需确保线程安全和语义清晰:
- 若用
AtomicLong累计总耗时:用addAndGet(microseconds)或accumulate(microseconds)(JDK9+) - 若记录单次耗时(如打点日志或上报):直接赋值
latencyUs = microseconds即可 - 若集成 Micrometer:
timer.record(microseconds, TimeUnit.MICROSECONDS)—— 它内部会自动处理单位转换
必须避开的坑
微秒级测量极其敏感,以下操作会让结果失真:
- 别在循环里反复调用 nanoTime():每次调用本身有开销(约 10–100 ns),测空循环会测出“调用开销”而非真实逻辑耗时
- 避免 JIT 干扰:首次运行可能被解释执行,建议预热(如循环执行 10k 次再正式测量)
- 别测包含 GC、线程切换、磁盘/网络的操作:这些引入毫秒级抖动,掩盖微秒级差异
-
不要用
System.currentTimeMillis():毫秒级精度,且受系统时钟调整影响,完全不适合
一个轻量、安全的封装示例
用于业务代码中快速埋点:
public static long measureMicros(Runnable task) {
long start = System.nanoTime();
task.run();
return (System.nanoTime() - start) / 1000;
}
<p>// 使用:
long us = measureMicros(() -> doFastCalculation());
metrics.recordLatency(us); // 推送至监控系统
这个封装把采样逻辑收拢,避免手误漏掉 end 调用,也方便统一加日志或异常兜底。


















