System.currentTimeMillis() 存在精度误差,因其依赖系统时钟粒度(Linux 1–10ms、Windows 15–16ms)、受NTP校时和手动改时影响,且不反映真实CPU执行时间;应改用System.nanoTime()测耗时。

System.currentTimeMillis() 在变量计时中存在明显精度误差,主要源于它不反映真实 CPU 执行时间,而是依赖系统时钟的“墙上时间”(wall-clock time)。它的误差不是编程错误,而是设计使然——它本就不是为高精度计时而生。
误差来源很实在
它底层通常调用 gettimeofday()(Linux/macOS)或类似系统 API(Windows),而这些接口受制于操作系统时钟粒度:
- Linux 一般为 1–10 毫秒,具体取决于内核配置和硬件;
- Windows 旧版本常见 15–16 毫秒,新版本有所改善但仍未达微秒级;
- 两次调用间隔若短于该粒度,返回值可能完全相同 → 耗时显示为 0,不代表真没耗时;
- NTP 校时、手动改系统时间会导致时间戳跳变甚至倒退,
end - start可能为负。
变量命名掩盖不了本质问题
即使你把变量起得再规范——比如 startTimeMs、endTimeMs、elapsedMs——只要底层用的是 currentTimeMillis(),就逃不开这些限制。常见误区包括:
- 用
int存储时间戳:跨天后溢出,结果翻转成负数; - 在方法入口取
start,但实际逻辑前还有校验、日志等非核心代码,测的不是目标段; - 异常路径未覆盖:
try里取了start,但catch或finally没取end,导致统计缺失; - 误把毫秒差当纳秒用,或直接拿去算超时阈值(如判断是否 >10ms),结果不可靠。
什么场景下误差会放大
以下情况会让误差更显著、更误导判断:
- 单次测量极短逻辑(如空循环、简单 getter):真实耗时远低于系统时钟分辨率,结果常为 0 或随机跳变;
- 高并发频繁调用:HotSpot 中
currentTimeMillis()在某些系统上存在锁竞争,实测并发调用百次耗时可达单线程的数百倍; - 跨设备/跨环境对比:同一段代码在 Windows 和 Linux 上测出的“耗时”可能差出一个数量级,只因系统时钟实现不同;
- 涉及休眠、挂起、NTP 同步的长时间运行任务:中间若被系统调整时间,差值包含校正量,非纯执行时间。
不换方案,至少守住底线
如果暂时无法替换,至少做到三点降低误判风险:
- 始终用
long接收,避免整型溢出; - 确保
start紧贴待测逻辑开始前,end覆盖所有出口(推荐try-finally包裹); - 对关键路径,别信单次结果——循环执行多次,取平均或观察分布趋势,而非紧盯一个数字。
真正要消除这类误差,就得换用 System.nanoTime():它基于 CPU 计数器,单调、抗校时、分辨率通常达微秒级,专为测执行耗时而设。只是记住——它的值本身无业务含义,只用于相减。

















