System.currentTimeMillis()用于获取真实世界时间点,适合日志、超时判断;System.nanoTime()用于精确测量时间间隔,适合性能测试。二者语义不同,不可混用。

区分 System.currentTimeMillis() 和 System.nanoTime() 的关键,在于理解它们的设计目的:前者用于表示“真实世界的时间点”,后者用于“精确测量时间间隔”。用错场景会导致逻辑错误或精度丢失。
用途不同:一个看“什么时候”,一个算“多久”
currentTimeMillis() 返回自 1970 年 1 月 1 日 00:00:00 UTC(即 Unix 纪元)以来的毫秒数,类型是 long。它和系统时钟同步,可能被 NTP 调整、手动修改或发生闰秒跳跃——因此不适合测耗时。
nanoTime() 返回的是一个**单调递增的纳秒级计时器值**,不对应任何日历时间,只反映从某个未指定起点开始经过的纳秒数。它不受系统时钟调整影响,精度更高(通常为微秒或更好),专为性能测量而生。
- ✅ 正确用法:
startTime = System.currentTimeMillis(); doWork(); durationMs = System.currentTimeMillis() - startTime;—— 仅适用于粗略估算、日志打点、超时判断(如if (System.currentTimeMillis() - start > 5000) timeout();) - ✅ 正确用法:
start = System.nanoTime(); doWork(); elapsedNs = System.nanoTime() - start;—— 测方法执行时间、循环开销、基准测试(JMH 底层也依赖它) - ❌ 错误用法:
System.nanoTime()做定时调度(比如“在 10 秒后执行”),因为它无法映射到 wall-clock 时间 - ❌ 错误用法:
System.currentTimeMillis()测微秒级差异,因它的分辨率通常只有 10–16ms(取决于 OS),多次调用可能返回相同值
精度与稳定性差异明显
currentTimeMillis() 的实际精度由底层操作系统决定:Windows 上常为 15.6ms,Linux 可能为 1–10ms。它还可能倒流(如系统时钟被向后校准),导致差值为负。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
nanoTime() 在现代 JVM 上基本都能提供亚微秒级稳定分辨率,且保证单调性(即 nanoTime() 后续调用结果一定 ≥ 之前调用)。但要注意:它的数值本身无意义,不能直接转成日期或传给 Thread.sleep() 等需要绝对时间的 API。
- ⚠️ 注意:
nanoTime()的数值范围极大(约 292 年才溢出),但不要把它当成时间戳使用 - ⚠️ 注意:两个方法返回值单位不同,混用会引发数量级错误(比如把纳秒当毫秒除以 1000 得到错误的秒数)
典型误用场景与修复建议
常见陷阱包括用 currentTimeMillis() 做高频轮询超时判断、在压测中统计单次响应时间、或试图用 nanoTime() 计算“当前几点”。这些都会引入不可靠行为。
- 轮询等待某条件成立?用
currentTimeMillis()判断总耗时是否超限即可,内部循环里不必反复调用它;更推荐用LockSupport.parkNanos()或带超时的并发工具类 - 想测一段代码执行了多长时间?必须用
nanoTime(),并确保两次调用紧邻目标代码(避免 JIT 编译、GC 等干扰) - 需要“现在是几点几分”?只能用
currentTimeMillis()配合Instant.now()或LocalDateTime;nanoTime()完全不适用
一句话总结选择原则
问自己两个问题:
我要知道“事件发生在真实世界的哪个时刻”吗?→ 选 currentTimeMillis()
我要知道“两件事之间隔了多久”吗?→ 选 nanoTime()
不复杂但容易忽略:它们不是精度高低的简单替代关系,而是语义完全不同的两种时间抽象。

















