1. 方法定义
public static long nanoTime()
- 返回当前JVM的高精度时间值(纳秒)
- 返回值类型:
long
2. 功能说明
- 高精度计时:提供纳秒级时间测量(实际精度依赖硬件)
- 相对时间源:测量任意两点间的时间间隔(非日历时间)
- 单调递增:不受系统时间更改影响(即使手动调整系统时间)
- JVM范围:仅在同一个JVM实例中保证可比性
3. 示例代码
public class NanoTimeDemo {
public static void main(String[] args) {
// 测量代码执行时间
long start = System.nanoTime();
// 被测代码
int sum = 0;
for (int i = 0; i < 1_000_000; i++) {
sum += i;
}
long end = System.nanoTime();
long duration = end - start;
System.out.println("计算耗时: " + duration + " 纳秒");
System.out.println("约合: " + (duration / 1_000_000.0) + " 毫秒");
// 超时检测
long timeout = TimeUnit.SECONDS.toNanos(3); // 3秒超时
long taskStart = System.nanoTime();
while (!isTaskDone()) {
if (System.nanoTime() - taskStart > timeout) {
System.err.println("任务超时!");
break;
}
// 继续执行任务...
}
}
private static boolean isTaskDone() {
// 模拟任务状态
return Math.random() > 0.8;
}
}
4. 使用技巧
- 性能基准测试:精确测量代码段执行时间
- 超时控制:在循环中检测操作是否超时
- 时间间隔比较:
long start = System.nanoTime(); // ... long elapsedNanos = System.nanoTime() - start;
- 时间单位转换:
double seconds = TimeUnit.NANOSECONDS.toSeconds(elapsedNanos);
5. 常见错误
误作绝对时间使用
// 错误!不能转换为日期 long now = System.nanoTime(); Date date = new Date(now); // 完全错误的值
- 正确替代:
System.currentTimeMillis()
- 正确替代:
跨JVM比较
// JVM1: long t1 = System.nanoTime(); // JVM2: long t2 = System.nanoTime(); // 错误!t1和t2不能直接比较
忽略精度限制
// 某些系统实际精度为微秒级 long t1 = System.nanoTime(); long t2 = System.nanoTime(); System.out.println(t2 - t1); // 可能显示0(实际有延迟)
6. 注意事项
- 非绝对时间:返回值与1970年无关,仅表示纳秒计数器
- 系统依赖:
- Windows:通常精度≈100纳秒
- Linux:通常精度≈1纳秒
- 可能回退:在NTP调整等极端情况下可能非单调(极罕见)
- 休眠影响:系统休眠期间可能暂停计数
7. 最佳实践与性能优化
预热测量:避免首次测量受JIT编译影响
// 预热 for (int i = 0; i < 10_000; i++) { /* 被测代码 */ } // 正式测量 long start = System.nanoTime(); // ...
多次测量取中位数:
long[] times = new long[10]; for (int i = 0; i < 10; i++) { long s = System.nanoTime(); // 被测代码 times[i] = System.nanoTime() - s; } Arrays.sort(times); long median = times[times.length/2];
避免微基准测试陷阱:
// 错误:JIT可能优化掉空循环 long start = System.nanoTime(); for (int i = 0; i < 1_000_000; i++); // 被优化! long duration = System.nanoTime() - start;
与
currentTimeMillis
对比使用: | 场景 | 推荐方法 | |--------------------------|-----------------------------| | 代码性能测量 |nanoTime()
| | 日历时间/绝对时间 |currentTimeMillis()
| | 超时控制(>1秒) |currentTimeMillis()
| | 超时控制(<1秒) |nanoTime()
|
8. 精度实测示例
public class PrecisionTest {
public static void main(String[] args) {
long last = System.nanoTime();
long minDiff = Long.MAX_VALUE;
for (int i = 0; i < 1000; i++) {
long current = System.nanoTime();
long diff = current - last;
if (diff > 0 && diff < minDiff) {
minDiff = diff;
}
last = current;
}
System.out.println("最小可测量间隔: " + minDiff + " 纳秒");
System.out.println("系统实际精度: ~" + (minDiff > 1000 ?
(minDiff/1000) + " 微秒" : minDiff + " 纳秒"));
}
}
9. 总结
特性 | 说明 |
---|---|
核心用途 | 高精度时间间隔测量 |
精度范围 | 纳秒级(实际精度依赖硬件/OS) |
时间参考 | 任意起点(仅限JVM内部比较) |
线程安全 | 是 |
系统时间影响 | 不受系统时间更改影响 |
适用场景 | 微基准测试、超时控制、性能分析 |
不适用场景 | 日历时间、跨JVM比较、持久化时间戳 |
黄金实践原则:
- 只用于时间差:始终计算两个
nanoTime()
值的差值 - JVM内部使用:不在JVM实例间比较结果
- 理解精度限制:实际精度通常为微秒级(Windows)或纳秒级(Linux)
- 长周期用毫秒:超过1秒的测量优先考虑
currentTimeMillis()
- 基准测试预热:避免JIT编译干扰首次测量结果
在99%的应用场景中,遵循以下决策树:
需要测量短时间间隔(<1s)? → 使用nanoTime()
需要绝对时间/日历时间? → 使用currentTimeMillis()
或Instant.now()
需要跨JVM的时间比较? → 使用网络时间协议(NTP)同步的系统时钟