System.currentTimeMillis()在高并发下不仅性能差,更关键的是不准:毫秒级精度不足导致重复时间戳、逻辑乱序、耗时测量失真及系统调用噪声,应按场景选用nanoTime、Instant或缓存方案。

高并发下用 System.currentTimeMillis() 不只是慢,更关键的是“不准”——它既难保证精度,也难维持逻辑一致性。
毫秒级分辨率根本撑不住高频调用
多数操作系统(如 Linux)的时钟更新粒度在 10–16ms 之间。这意味着:同一毫秒内发起的成百上千次调用,返回值完全一样。对需要时间戳唯一性的场景(比如生成订单号、事件排序、防重幂等),这会直接导致冲突或乱序。
- 1000 个线程在 5ms 内同时调用,很可能 90% 都拿到同一个毫秒值
- 分布式 ID 生成器若只依赖 currentTimeMillis() + 自增序列,极易因时间回退或重复而产生重复 ID
- 日志打点若靠时间戳排序,同一毫秒内的多条日志顺序不可靠
跨系统调用中测出的“耗时”常含大量噪声
用 start = System.currentTimeMillis() 和 end = System.currentTimeMillis() 做差,并不能真实反映业务执行时间。尤其在 HTTP 请求、数据库访问、RPC 等跨系统操作中,结果混入了大量非业务延迟:
Agent 记忆系统 — 五路融合检索 + 双时间线 + 因果链 + Spirit管家 + 记忆回声 + 弹性配置 + Circuit Breaker + GDPR合规 + 192项安全审计修复
- JVM GC 暂停期间系统时间照常走,但你的代码没运行——差值里却算进了这几百毫秒
- 线程被调度器挂起几十毫秒后才继续执行,这部分也被计入“耗时”
- NTP 时间校正或用户手动调时,可能让 end - start 变成负数或异常大值
多线程争抢共享时钟源带来性能抖动
每次调用都触发 JNI 进入内核态(如 Linux 的 gettimeofday()),而底层时钟源是全局共享资源。高并发下多个线程排队等待内核响应,实测显示:100 次并发调用耗时可能是单线程的 8–40 倍,且波动剧烈。
- 不是方法本身有锁,而是操作系统层面的资源竞争
- 线程越多、调用越密,平均延迟越高、方差越大
- 这种抖动会放大到上层监控指标(如 P99 响应时间失真)
替代方案要按用途区分选型
没有银弹,关键看你要什么:
- 测代码执行耗时 → 用
System.nanoTime():纳秒级、单调递增、不受系统时间调整影响 - 记录事件发生时刻(如日志时间、消息时间戳)→ 用
Instant.now():语义清晰、时区安全、可序列化 - 需要高频读取且允许毫秒级误差 → 用 volatile 缓存(如每 1–5ms 更新一次全局时间变量)
- 生成唯一 ID 或需严格单调性 → 结合机器 ID + 序列号 + nanoTime 或 Snowflake 算法,别只押注 currentTimeMillis()

















