system.currenttimemillis()精度不够,通常为1–15ms,不单调且受ntp校时影响,仅适用于秒级粗略计时;测短耗时应选system.nanotime()或jmh。

用 System.currentTimeMillis() 测耗时,精度够不够?
System.currentTimeMillis() 返回的是自 1970-01-01 00:00:00 UTC 起的毫秒数,底层通常基于系统时钟(如 gettimeofday 或 Clock_gettime(CLOCK_REALTIME)),它不保证高精度或单调性。在多数 Linux/macOS 上,实际分辨率常为 1–15ms;Windows 上可能更差(尤其旧版本)。这意味着:
- 两次调用间隔若小于系统时钟粒度,可能返回相同值
- 遇到系统时间被 NTP 调整、手动校时,结果可能“倒退”或跳变
- 不适合测
所以,它只适用于粗略估算、日志打点、或对精度要求不高的场景(比如“这个 HTTP 请求花了多少秒”)。
System.currentTimeMillis() 正确用法:两步取差,别漏减号
核心就是:执行前记一次,执行后记一次,后减前。
long start = System.currentTimeMillis(); // ⬇️ 这里放你要测的代码段 doSomethingExpensive(); long end = System.currentTimeMillis(); <p>long elapsed = end - start; // 注意:是 end - start,不是 start - end</p>
常见错误包括:
-
start和end类型写成int,导致溢出(尤其跨天时) - 把
elapsed当作纳秒或微秒用(它单位是毫秒) - 在循环内反复调用
System.currentTimeMillis()测单次调用——开销本身可能和被测代码量级接近,干扰结果 - 忘记捕获异常但没处理,导致
start记录了,end没执行到,变量未定义
比 System.currentTimeMillis() 更准的替代方案有哪些?
如果真需要测
-
System.nanoTime():基于 CPU 计数器,精度通常达纳秒级(实际有效位约微秒),且严格单调。适合性能分析、基准测试。 -
Instant.now()(Java 8+):语义清晰,但底层仍可能调用System.currentTimeMillis(),精度无提升。 - 第三方库如
org.openjdk.jmh:专为微基准测试设计,自动预热、GC 控制、统计置信区间,避免手写计时的陷阱。
注意:System.nanoTime() 的绝对值无业务意义,只用于差值计算;它的值可能很大(纳秒级),但相减结果仍是靠谱的耗时。
线上日志中用 System.currentTimeMillis() 打点要注意什么?
它常被用于记录“请求开始时间”“SQL 执行起止”等可观测性打点:
- 别在 finally 块里硬写
System.currentTimeMillis() - start:如果start是方法参数传入,而方法被重载或代理拦截,可能错配 - 日志中建议同时输出
start和elapsed,方便排查时钟漂移(比如发现elapsed是负数,就说明系统时间被回拨了) - 避免在高频循环里每轮都打完整日志——改用采样或聚合(如每 100 次记一次平均)
真正难的不是怎么调用这个函数,而是判断你是否真的需要它——很多“耗时问题”的根因其实在 I/O 阻塞、锁竞争或 GC,而不是计时方式本身。










