要用 System.nanoTime() 真正看清算法性能,关键不是“测一次”,而是让测量结果可比、可信、不被干扰;它提供单调高精度间隔计时,需预热、防优化、减干扰,并正确转换纳秒为微秒以避免精度丢失。

要用 System.nanoTime() 真正看清算法性能,关键不是“测一次”,而是让测量结果可比、可信、不被干扰。
只用 nanoTime() 测时间差,别碰 currentTimeMillis()
两者定位完全不同:currentTimeMillis() 返回的是“墙上时间”,精度通常只有毫秒级,且受系统时间调整影响——比如运维改了服务器时间,你的耗时就可能变负数;而 nanoTime() 是单调递增的高分辨率计时器,专为测量间隔设计。它不告诉你现在几点,只告诉你“从 A 到 B 过了多久”。实际分辨率取决于系统(Linux 通常 ~10–15 纳秒,Windows 约 100 纳秒),但足够覆盖微秒级分析需求。
纳秒转微秒:选对除法方式才不丢精度
得到纳秒差后,不能简单 durationNs / 1000 就完事。Java 整数除法会直接截断余数,比如 1999 纳秒 → 1 微秒,丢失近一半信息。根据用途选合适方式:
-
日志打点或阈值判断(如“是否超 50μs”):用
durationNs / 1000,整数截断够用 -
平均耗时统计或绘图:用
durationNs / 1000.0,保留小数,避免系统性低估 -
报告人类可读结果(如“约 2.3μs”):用
Math.round(durationNs / 1000.0),四舍五入更直观
避开常见干扰,让数据真实反映算法本身
一次调用测出的数字,大概率不是算法的真实开销,而是 JVM 预热、GC、上下文切换甚至计时器自身开销的混合体:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 先预热:循环执行目标代码至少 1000 次,丢弃前 100 次结果,让 JIT 编译完成、类加载完毕
- 防优化:把计算结果赋给
volatile变量(如volatile int sink),避免 JIT 把整个计算优化掉 - 减干扰:测量块内不打印、不创建对象、不触发 GC;关闭 IDE 日志、暂停后台程序
- 单线程跑:确保所有测量都在同一线程执行,排除调度抖动影响
一个轻量但靠谱的实测模板
不需要 JMH,也能快速验证算法改动效果:
volatile int sink;
long totalNanos = 0;
int warmup = 100, iterations = 10000;
<p>// 预热
for (int i = 0; i < warmup; i++) {
sink = yourAlgorithm();
}</p><p>// 正式测量
for (int i = 0; i < iterations; i++) {
long start = System.nanoTime();
sink = yourAlgorithm(); // 结果必须被使用
long end = System.nanoTime();
totalNanos += (end - start);
}</p><p>double avgMicros = totalNanos / (double) iterations / 1000.0;
System.out.printf("平均 %.2f μs%n", avgMicros);
不复杂但容易忽略


















