system.currenttimemillis()用于绝对时间操作,如日志、缓存过期;system.nanotime()专用于高精度耗时测量,单调递增且不受系统时钟调整影响。

System.currentTimeMillis() 返回自 1970 年 1 月 1 日 00:00:00 UTC(即 Unix 纪元)以来的毫秒数,类型为 long;System.nanoTime() 返回的是一个以纳秒为单位的、**相对的、高精度的时间值**,不对应任何现实时钟,仅用于测量时间间隔。
用途差异:什么时候该用哪个?
这是面试中最常被追问的核心点:
- currentTimeMillis:适合做“绝对时间”相关操作,比如日志打点、缓存过期判断、定时任务调度、数据库时间戳记录等。它和系统时钟同步,可能因 NTP 校正或手动调时而跳变(向前或向后)。
- nanoTime:专为**性能测量、耗时统计、基准测试(benchmark)** 设计。它不受系统时钟调整影响,单调递增,精度通常达纳秒级(实际取决于底层硬件和 OS,Java 不保证绝对纳秒精度,但保证相对精度和单调性)。
精度与稳定性:别被“nano”字面意思骗了
虽然名字叫 nanoTime,但它返回的不是“真实纳秒”,而是 JVM 提供的一个高分辨率、单调递增的计数器值(例如基于 CPU 的 TSC 寄存器或 OS 的高精度计时器)。关键特性是:
- 两次调用差值可准确反映真实经过时间(只要没溢出);
- 不能用它计算“当前时刻”,因为起点未知、无意义;
- 不同 JVM 实例或重启后,nanoTime 值不可比;
- 极端情况下(如某些虚拟机或老旧硬件),实际分辨率可能是微秒甚至毫秒级,但差值仍可靠。
常见误用与面试陷阱
面试官常通过错误代码考察理解深度:
- ❌ 用
nanoTime()做超时判断(如if (nanoTime() > deadline) ...)——错!deadline 应基于currentTimeMillis或SystemClock类型,否则无法对齐真实时间。 - ❌ 把
nanoTime()结果直接转成日期/字符串——毫无意义,它不是时间戳。 - ❌ 在循环中高频调用
currentTimeMillis()测微秒级耗时——精度不够,且可能因系统时钟抖动导致负数结果。 - ✅ 正确姿势:
long start = System.nanoTime(); doWork(); long costNs = System.nanoTime() - start;
扩展提醒:Java 8+ 更推荐的新方式
虽然这两个仍是基础 API,但现代开发中建议优先考虑:
-
Instant.now()替代currentTimeMillis()做绝对时间(语义更清晰、支持纳秒级 Instant); -
Duration.between(start, end)替代手算 nanoTime 差值(类型安全、可读性强); - 真正需要高精度压测时,用 JMH(Java Microbenchmark Harness),它会自动处理预热、GC 干扰、JIT 影响等问题,比裸写 nanoTime 可靠得多。











