system.currenttimemillis()结果常为0因其毫秒级精度且受系统时钟调整影响,适合>10ms的粗略耗时统计;system.nanotime()更可靠,具高精度、单调性,专用于测量经过时间,但需正确单位换算。

用 System.currentTimeMillis() 测时间,为什么结果经常是 0?
因为它的精度通常是毫秒级,且受系统时钟调整影响。在执行很快的代码(比如一个空循环或简单计算)时,System.currentTimeMillis() 两次调用返回的值很可能相同,差值就是 0。
- 适用场景:粗略统计“用户感知耗时”,比如接口整体响应、文件读写、网络请求等 >10ms 的操作
- 不适用:微基准测试、算法内部循环耗时、纳秒级精度需求
- 注意:
System.currentTimeMillis()可能因 NTP 同步、手动改系统时间而跳变,导致负值或突增
为什么 System.nanoTime() 是更可靠的计时选择?
System.nanoTime() 返回的是从某个未指定起点开始的纳秒数,不受系统时钟修改影响,且精度更高(通常为微秒甚至纳秒级),专为测量经过时间设计。
- 它不能用于获取“当前时间”,只适合算差值:
long elapsed = System.nanoTime() - start; - 不同 JVM 实现下,其底层可能基于
CLOCK_MONOTONIC(Linux)或QueryPerformanceCounter(Windows),但行为一致:单调、高精度、无跳变 - 注意:虽然叫 nanoTime,但实际分辨率未必是 1 纳秒;可通过
ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors()配合多次采样估算,但一般不用深究
真实代码里怎么写才不容易出错?
最常见错误是混用两种方法、漏减、或把 nanoTime() 当成绝对时间用。
- 始终成对使用同一方法:
long start = System.nanoTime(); /* do something */ long end = System.nanoTime(); - 别用
currentTimeMillis()减nanoTime()—— 单位和起点都不同,结果无意义 - 如果要输出易读耗时,记得单位转换:
double ms = (end - start) / 1_000_000.0;,而不是除以 1000 - 避免在循环内反复调用计时函数测单次操作:JVM 优化(如 JIT)会让首次执行慢、后续飞快,应做 warmup + 多次采样取平均
性能开销本身要不要考虑?
System.nanoTime() 调用本身有开销,但现代 JVM 下通常在 10–100 纳秒量级,远小于多数业务逻辑。真正要警惕的是误把它嵌进高频热点路径里。
- 比如在每轮 for 循环里都调一次
nanoTime()来“看哪次慢”,反而让 profiling 失真 - 如果只是调试用,建议用 JFR(Java Flight Recorder)或 async-profiler,它们开销更低、信息更全
-
currentTimeMillis()开销略小,但精度缺陷让它在性能敏感场景中得不偿失
精度和语义差异比性能更重要。很多人抄了示例代码就跑,却没意识到 currentTimeMillis() 在本地快速测试中根本测不出东西,而 nanoTime() 的单位换算写错一位(比如除以 1000 而不是 1_000_000)会导致结果放大 1000 倍——这种细节,一不留神就浪费半天排查时间。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











