system.currenttimemillis() 不适合计时器逻辑,因其是易受系统时间调整影响的挂钟而非单调时钟,会导致负耗时、精度不足(10–15ms)、跨线程/节点时钟不同步等问题;应依场景选用 system.nanotime()(相对耗时)、instant.now()(绝对时刻)等替代方案。

System.currentTimeMillis() 不适合用在计时器逻辑中——它不是秒表,而是挂钟。一旦系统时间被手动调整或 NTP 自动校正,计时器就可能跳变、倒退甚至失效。
它会“倒流”,导致负耗时
计时器依赖“后减前”算差值,但 currentTimeMillis() 返回的是系统挂钟时间,受外部干预影响:
- 用户手动把系统时间往回调,比如从 14:30 改成 14:20,两次调用可能返回 1718720000000 → 1718719400000,差值为负
- NTP 同步时若发生大幅回拨(如修正 500ms 偏差),也会触发同样问题
- 日志里出现 “耗时: -127ms” 就是典型信号,说明计时逻辑已被破坏
精度不足,短间隔测不准
多数操作系统对 currentTimeMillis() 的实际分辨率只有 10–15ms:
- 想控制 300ms 防抖,但连续两次调用可能返回相同毫秒值,导致 duration = 0
- 在 Windows 上尤其明显,旧版本默认精度约 15.6ms,根本无法支撑亚百毫秒级判断
- 看似“已过 250ms”,实际可能只过了 10ms,也可能卡在 0ms,结果不可靠
跨线程/跨节点时钟不同步
计时器若涉及多线程协作或分布式协调,问题更突出:
- 多个线程共用一个 start 时间戳,但各自调用 currentTimeMillis() 获取的 end 值可能来自不同步的 CPU 核心或虚拟机时钟
- 容器环境、云主机常因 vCPU 暂停、热迁移导致本地时钟漂移,两台机器差值失真
- HTTP 超时判断若依赖服务端 currentTimeMillis() 减去客户端发包时间,网络延迟和时钟偏差会让阈值形同虚设
正确替代方案:按场景选 API
计时器逻辑必须区分“何时触发”和“持续多久”:
- 做超时等待、防抖、倒计时 → 用 System.nanoTime():单调、高精度、不受系统调时影响,适合计算相对经过时间
- 调度任务到某个绝对时刻(如“明天 9 点执行”)→ 用 Instant.now() 或 LocalDateTime.now().atZone(ZoneId.systemDefault()),再转为调度框架可识别的时间点
- 需要兼顾精度与可观测性(如链路追踪中的 span 时间)→ 用 nanoTime() 记录起止,再用 currentTimeMillis() 打上 wall-clock 时间戳作参考
- 高频循环内需反复判断是否超时 → 提前缓存 nanoTime() 起点,避免每次调用开销;别在循环里反复调用 currentTimeMillis()










