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. 常见错误

  1. 误作绝对时间使用

    // 错误!不能转换为日期
    long now = System.nanoTime();
    Date date = new Date(now); // 完全错误的值
    
    • 正确替代:System.currentTimeMillis()
  2. 跨JVM比较

    // JVM1:
    long t1 = System.nanoTime();
    // JVM2:
    long t2 = System.nanoTime();
    // 错误!t1和t2不能直接比较
    
  3. 忽略精度限制

    // 某些系统实际精度为微秒级
    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比较、持久化时间戳

黄金实践原则

  1. 只用于时间差:始终计算两个nanoTime()值的差值
  2. JVM内部使用:不在JVM实例间比较结果
  3. 理解精度限制:实际精度通常为微秒级(Windows)或纳秒级(Linux)
  4. 长周期用毫秒:超过1秒的测量优先考虑currentTimeMillis()
  5. 基准测试预热:避免JIT编译干扰首次测量结果

在99%的应用场景中,遵循以下决策树:
需要测量短时间间隔(<1s)? → 使用nanoTime()
需要绝对时间/日历时间? → 使用currentTimeMillis()Instant.now()
需要跨JVM的时间比较? → 使用网络时间协议(NTP)同步的系统时钟