1. 概述
本文将探讨在Java中测量代码执行时间的多种方法。虽然这看起来简单,但实际操作中存在几个需要警惕的坑。
我们将从标准Java类库到第三方工具包,全面分析各种时间测量方案的优缺点和适用场景。
2. 基础测量方案
2.1. currentTimeMillis()
初次接触时间测量需求时,很多开发者会这样写:
long start = System.currentTimeMillis();
// 待测代码
long finish = System.currentTimeMillis();
long timeElapsed = finish - start;
这段代码逻辑清晰:获取开始时间戳 → 执行目标代码 → 获取结束时间戳 → 计算差值。但结果往往不准确,因为currentTimeMillis()
测量的是墙上时钟时间(wall-clock time)。
⚠️ 墙上时钟时间容易受以下因素干扰:
- 系统时间手动调整
- 闰秒(leap second)影响
- NTP时间同步服务校准
2.2. nanoTime()
java.lang.System
类提供了更可靠的nanoTime()
方法。根据JDK文档:
"此方法仅用于测量经过时间,与任何系统时间或墙上时钟时间概念无关"
使用方式与前者类似:
long start = System.nanoTime();
// 待测代码
long finish = System.nanoTime();
long timeElapsed = finish - start;
✅ 关键优势:
- 专门为时间测量设计
- 不受系统时钟调整影响
- 精度可达纳秒级
❌ 需要注意:
- 返回值单位是纳秒,需手动转换(毫秒需除以1,000,000)
- 虽然精度高,但实际更新频率(分辨率)可能低于纳秒级
- 文档仅保证分辨率不低于
currentTimeMillis()
3. Java 8 新方案
Java 8 引入的java.time
包提供了更现代的时间处理方案,核心类包括Instant
和Duration
。这些类都是不可变、线程安全的,并使用独立的Java时间刻度(Java Time-Scale)。
3.1. Java时间刻度
传统时间体系将一天分为:
- 24小时 × 60分钟 × 60秒 = 86,400秒
但实际天文日长度存在微小差异。UTC时间刻度允许一天包含86,399或86,401秒(国际秒定义基于铯133原子辐射周期),以保持与太阳日的同步。
Java时间刻度则将每个日历日严格划分为86,400秒,不处理闰秒问题。
3.2. Instant
类
Instant
表示时间轴上的瞬时点,本质是从1970-01-01T00:00:00Z开始的数字时间戳。通过Instant.now()
获取当前时间戳:
Instant start = Instant.now();
// 待测代码
Instant finish = Instant.now();
long timeElapsed = Duration.between(start, finish).toMillis();
✅ 优势:
- 使用
Duration.between()
自动计算时间差 - 支持灵活的时间单位转换(毫秒/秒/纳秒等)
- 避免手动计算错误
4. StopWatch
工具类
Apache Commons Lang提供的StopWatch
是更专业的计时工具,适合复杂场景。
4.1. Maven依赖
在pom.xml
中添加:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
最新版本可在Maven仓库查询。
4.2. 使用StopWatch
测量时间
基础用法:
StopWatch watch = new StopWatch();
watch.start();
// 待测代码
watch.stop();
System.out.println("Time Elapsed: " + watch.getTime()); // 输出: Time Elapsed: 2501
✅ 进阶特性:
suspend()
/resume()
:暂停/恢复计时split()
:记录分段耗时- 支持多任务计时(需调用
reset()
重置)
❌ 注意事项:
- 非线程安全
- 需要额外依赖
5. 总结
Java中测量时间的方法对比:
方法 | 精度 | 线程安全 | 适用场景 |
---|---|---|---|
currentTimeMillis() |
毫秒 | 是 | 简单场景(不推荐) |
nanoTime() |
纳秒 | 是 | ✅ 推荐基础方案 |
Instant /Duration |
纳秒 | 是 | Java 8+项目 |
StopWatch |
毫秒/纳秒 | 否 | 复杂计时需求 |
简单粗暴的结论:
日常开发直接用nanoTime()
足够,代码简洁且准确。对于专业基准测试(benchmarking),建议使用JMH等框架,而非手动计时——这已超出本文讨论范围。