应根据用途选择:测耗时用 nanotime(),记时间点用 currenttimemillis();前者单调递增、精度高,后者对应真实时间、可读性强,混用会导致负值、跳变或精度丢失。

选对方法比调用本身更重要:测“多久”用 nanoTime(),记“什么时候”用 currentTimeMillis()。混用不仅得不到准确结果,还可能引入负值、跳变或精度丢失。
用途决定选择:一个管时刻,一个管间隔
System.currentTimeMillis() 返回的是自 1970 年 1 月 1 日起的毫秒数,对应真实世界时间(wall-clock time)。它适合打日志时间戳、判断超时、计算有效期、与数据库或前端交互等需要可读时间点的场景。
System.nanoTime() 返回的是从某个未知起点开始的纳秒计数,不关联任何日历时间,只保证单调递增。它专为测量耗时而生——比如方法执行、循环开销、基准测试。
- 用
currentTimeMillis()测一段空循环?很可能得到 0 —— 因为系统时钟精度通常只有 10–16ms - 用
nanoTime()设置 5 秒后执行任务?做不到 —— 它无法映射到具体时间点 - 把两者相减(如
nanoTime() - currentTimeMillis())?数值无意义,单位和起点都不同
精度与稳定性差异明显
currentTimeMillis() 受操作系统限制,Windows 下典型精度约 15.6ms,Linux 约 1–10ms;且可能因 NTP 同步、手动改时间而倒流或突跳,导致差值为负。
nanoTime() 在现代 JVM 上基本稳定提供微秒级甚至更高分辨率,始终单调递增,不受系统时钟调整影响。但它返回的数字本身不能转成日期,也不能传给 Thread.sleep() 或定时器 API。
- 多次调用
currentTimeMillis()得到相同值?正常,不代表没耗时 -
nanoTime()值很大(比如几十万亿)?正常,它是相对计数,不是 Unix 时间 - 想确认精度?不必深究底层,只需记住:它适合测差值,不适合做绝对时间
实际写法:避免常见错误
测耗时最简写法就两行,但细节决定是否可靠:
- 粗略统计(>10ms 操作):
long start = System.currentTimeMillis(); doWork(); long ms = System.currentTimeMillis() - start; - 精确测量(任意长度):
long start = System.nanoTime(); doWork(); long ns = System.nanoTime() - start; double ms = ns / 1_000_000.0; - 输出易读耗时:除以
1_000_000.0得毫秒(保留小数),或用Math.round(ns / 1_000_000.0)四舍五入 - 别在高频循环里反复调
nanoTime()—— 开销虽小(10–100ns),但会干扰真实性能表现
什么情况下该换方法?
当出现以下任一情况,说明当前用法已不合适:
- 测出来总是 0 或波动极大 → 换
nanoTime() - 代码上线后某天耗时突变为负数 → 很可能是系统时间被回拨,
currentTimeMillis()不再可靠 - 需要 JMH 级别的基准测试 → 必须用
nanoTime(),JMH 底层也依赖它 - 日志里时间戳要能被 Grafana 解析、被用户看懂 → 只能用
currentTimeMillis()或Instant.now()











