system.nanotime()是算法竞赛中唯一可靠的本地计时工具,用于精准测量微秒级耗时,需通过差值计算、预热采样、防止jit优化,并避免在并发或休眠场景误用。

在算法竞赛中,System.nanoTime() 是唯一值得信赖的本地计时工具,它不依赖系统时间、不受NTP校准或手动调时影响,能稳定捕捉微秒级耗时差异——这对判断边界复杂度(如 O(n log n) vs O(n²))、验证常数优化效果、排查超时风险至关重要。
测单次运行耗时,必须做差值
不能直接打印 nanoTime() 的返回值,它只是从JVM启动起的纳秒偏移量,无业务含义。正确写法是:
- 在算法代码前立即记录 start = System.nanoTime()
- 在算法结束后立即记录 end = System.nanoTime()
- 耗时 = end - start(单位:纳秒),转微秒除以1000,转毫秒除以1_000_000
例如测量快排10⁵个随机整数:
long start = System.nanoTime();
quickSort(arr, 0, arr.length - 1);
long ns = System.nanoTime() - start;
System.out.printf("耗时 %.2f ms%n", ns / 1_000_000.0);
避免单次测量噪声,用最小值或多次平均
一次调用可能受JIT预热、缓存未命中、线程调度延迟干扰。竞赛调试阶段建议:
- 预热:先执行5–10次,不计入结果
- 采样:再连续运行100–1000次,取最小值(反映最优路径性能)或平均值(评估稳定开销)
- 注意:不要用 currentTimeMillis() 替代,它在毫秒级内常返回相同值,对短算法永远显示“0ms”
防止JIT优化掉关键计算
如果算法结果未被使用,JVM可能在编译期直接优化掉整个逻辑,导致测出“0纳秒”。必须确保结果参与后续不可省略的操作:
- 将返回值赋给 volatile 变量(如 volatile long sink)
- 或用于简单输出、数组写入、条件判断等无法被消除的副作用
- 例如:sink ^= result; 比 result; 更可靠
慎用场景:别拿它当超时控制器或跨线程比对依据
nanoTime() 在单线程内精准,但竞赛代码若含并发或阻塞操作,需注意:
- 不要在 sleep() 或 wait() 前后用 nanoTime() 算“纯CPU耗时”,休眠时间也会被计入
- 不同线程调用 nanoTime() 的值不能直接相减比延迟,线程迁移CPU核心可能导致TSC偏差
- 它不适用于模拟真实世界超时(如“3秒内必须返回”),该用 currentTimeMillis() 或 Duration
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











