用 system.currenttimemillis() 测时间结果常为 0,因其毫秒级精度不足;应优先使用纳秒级、单调递增的 system.nanotime() 测耗时,且起止时间需紧贴被测逻辑,避免干扰。

用 System.currentTimeMillis() 测时间,为什么结果总是 0?
因为这个方法精度是毫秒级,如果代码执行太快(比如只做几次加法、字符串拼接),起止时间戳可能完全一样,差值就是 0。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 确保被测代码有足够耗时,比如循环 10 万次、读一个文件、调一次本地 HTTP 接口
- 别在 IDE 的“热加载”或“debug 模式”下测——JIT 优化没生效,结果不反映真实性能
- 单次测量意义不大,要重复多次取平均值,最好用 JMH 这类专业工具
System.currentTimeMillis() 和 System.nanoTime() 怎么选?
前者返回的是“挂钟时间”,受系统时间调整影响(比如 NTP 同步、手动改时间);后者是单调递增的纳秒级计时器,专为性能测量设计。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 测程序运行耗时,一律优先用
System.nanoTime(),更准、不受系统时间干扰 -
System.currentTimeMillis()只适合记录“什么时候发生的”,比如日志打点、缓存过期时间 - 注意:
System.nanoTime()返回值不是绝对时间,不能和日期转换,差值才有意义
写错顺序导致时间测量失效的典型错误
常见现象:测出来的时间比预期大很多,甚至负数(虽然极少见,但可能发生在跨线程或系统时间跳变时)。
本文档是Groovy入门教程;简单地说,Groovy 是下一代的java语言,跟java一样,它也运行在 JVM 中。作为跑在JVM中的另一种语言,groovy语法与 Java 语言的语法很相似。同时,Groovy 抛弃了java烦琐的文法。同样的语句,使用groovy能在最大限度上减少你的击键次数——这确实是“懒惰程序员们”的福音。感兴趣的朋友可以过来看看
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 起始时间必须在被测逻辑 之前 立即获取,结束时间在 之后 立即获取,中间不要穿插日志、打印、异常处理等无关操作
- 别把开始时间变量写成类字段——多线程下会互相覆盖
- 示例正确写法:
long start = System.nanoTime();<br>doSomethingExpensive();<br>long end = System.nanoTime();<br>System.out.println("耗时: " + (end - start) + " ns");
在 Spring 或 Web 应用里测接口耗时,直接套 System.nanoTime() 会踩什么坑?
问题不在计时本身,而在“测的位置”不对:比如在 Controller 里测,漏掉了 Filter、AOP、序列化这些真实请求链路中的耗时环节。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 如果是调试单个方法,用
System.nanoTime()没问题;但测完整 HTTP 请求,得用拦截器(如HandlerInterceptor)或过滤器(Filter)包住整个请求生命周期 - 避免在异步方法(
@Async、CompletableFuture)里用局部变量存起始时间——线程切换后变量不可见 - 生产环境慎用,高频打点会拖慢性能;考虑用 Micrometer + Prometheus 这类轻量埋点方案
实际写的时候,最容易被忽略的是:时间差值类型要用 long,别用 int——跑久了会溢出。还有,别在循环里反复调用 System.nanoTime() 做条件判断,那开销本身就会进测量结果。









