选对时间测量方法比写对代码更影响性能结论可靠性:system.currenttimemillis()用于获取真实世界时间戳,适合日志、超时判断;system.nanotime()专为精确测耗时设计,具高分辨率与单调性,但仅适用于差值计算。

选对时间测量方法,比写对代码更影响性能结论的可靠性。System.nanoTime() 和 System.currentTimeMillis() 看似都是“取时间”,但语义、精度、稳定性完全不同——用错一个,测出来的数字就不是你想要的。
看“什么时候”还是算“多久”
这是最根本的区分点:
-
System.currentTimeMillis() 返回自 1970 年起的毫秒数,对应真实世界时间(wall-clock time)。适合打日志、生成时间戳、判断超时(如
if (System.currentTimeMillis() - start > 5000)) -
System.nanoTime() 返回的是 JVM 内部单调递增的纳秒计数,起点未知、无日历意义。只应做减法:
long elapsed = end - start,专为测耗时而生
精度和稳定性差异决定适用边界
毫秒级 API 在微秒场景下会失效,不是因为写错了,而是它本来就不支持:
- currentTimeMillis() 实际分辨率通常为 1–15ms(Windows 常见 15.6ms),多次调用可能返回相同值;还可能倒流(系统时间被手动调后)或跳变(NTP 校准)
- nanoTime() 在现代系统上普遍提供 10–100 纳秒级稳定分辨率,保证单调性(后续值 ≥ 前值),不受系统时钟干扰
- 注意:nanoTime() 的“纳秒”是单位,不是绝对精度;差值在 100ns 以下时往往已是噪声,不宜过度解读
怎么写才不白测
单次调用 nanoTime() 测一段代码,结果基本不可信。真正有效的测量需兼顾 JVM 行为与系统干扰:
- 先预热:用目标方法执行 1 万–10 万次,触发 JIT 编译和类初始化,避免把冷启动开销混入结果
- 多轮采样:正式测量至少 100 轮,每轮执行 1000 次以上目标逻辑,降低计时器自身开销占比
- 合理统计:记录每轮总耗时,除以次数得单次均值;最终取所有轮次均值的中位数,抗异常值干扰更强
- 隔离干扰:A/B 对比时,确保两者使用独立对象实例,各自完成完整预热,避免缓存、GC、JIT 状态交叉污染
常见误用陷阱
这些错误不会报错,但会让数据失去参考价值:
- 把 nanoTime() 当时间戳用——它不能转成日期,也不能传给
Thread.sleep()或定时调度 - 混用两种方法计算差值——
System.nanoTime() - System.currentTimeMillis()数学上无意义,单位和起点都不同 - 在高频循环里反复调用 nanoTime()——每次调用本身有 10–50ns 开销,反而扭曲测量目标
- 用 currentTimeMillis() 测快于 10ms 的操作——大概率返回 0,或因分辨率不足掩盖真实差异
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











