01 引言
开过过程中,经常会遇到一些耗时的方法。当我们需要定位耗时的方法时,就需要逐步打印耗时已确认耗时的方法。或者在写单元测试的时候,粗略的估算方法耗时,是不是经常使用System.currentTimeMillis()
去计算的。
今天,我们一起来整理一下可以使用那些方法计算耗时。
02 耗时计算方案
我们先罗列出常用的计算耗时的方法。我们需要模拟一个方法的耗时:
private void invokeMethod() {
try {
System.out.println(DateUtil.now() + " invokeMethod 方法执行中......");
// 模拟方法耗时:0~3000 ms
Thread.sleep(new Random().nextLong(3000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
2.1 System.currentTimeMillis()
System.currentTimeMillis()
毫秒级计算。
@Test
void test01() {
long start = System.currentTimeMillis();
invokeMethod();
long end = System.currentTimeMillis();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + (end - start) + "ms");
// 结果
/*
* 2025-07-11 14:19:55 invokeMethod 方法执行中......
* 2025-07-11 14:19:58 执行完毕,耗时:2421ms
*/
}
2.2 System.nanoTime()
System.nanoTime()
纳秒级计算,计算方式和 System.currentTimeMillis()
一致。
@Test
void test02() {
long start = System.nanoTime();
invokeMethod();
long end = System.nanoTime();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + (end - start) + "ns");
}
2.3 Java8 Instant
和 Duration
@Test
void test03() {
Instant start = Instant.now();
invokeMethod();
Instant end = Instant.now();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + Duration.between(start, end).toMillis() + "ms");
}
2.4 Spring
框架StopWatch
@Test
void test04() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
invokeMethod();
stopWatch.stop();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + stopWatch.getTotalTimeMillis() + "ms");
}
2.5 Apache
的StopWatch
@Test
void test05() {
org.apache.commons.lang3.time.StopWatch stopWatch = new org.apache.commons.lang3.time.StopWatch();
stopWatch.start();
invokeMethod();
stopWatch.stop();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + stopWatch.getTime() + "ms");
}
2.6 hutool
的StopWatch
@Test
void test06() {
cn.hutool.core.date.StopWatch stopWatch = new cn.hutool.core.date.StopWatch();
stopWatch.start();
invokeMethod();
stopWatch.stop();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + stopWatch.getTotalTimeMillis() + "ms");
}
2.7 Google
的Stopwatch
这里要注意的是Google
的Stopwatch
中的watch
为小写。
@Test
void test06() {
Stopwatch stopWatch = Stopwatch.createUnstarted();
stopWatch.start();
invokeMethod();
stopWatch.stop();
System.out.println(DateUtil.now() + " 执行完毕,耗时:" + stopWatch.elapsed().toMillis() + "ms");
}
2.8 阿里的Arthas
Arthas
作为一款在线的Java
诊断工具,被用作生产环境。和其他计算工具不同的是,这种方式没有代码的侵入性,启动Arthas
后执行命令后,等待方法执行即可。
方法
@RestController
public class TimeController {
@RequestMapping("/test")
public void test() {
try {
System.out.println(DateUtil.now() + " invokeMethod 方法执行中......");
Thread.sleep(new Random().nextLong(3000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
启动Arthas
选择当前运行的项目编号:
输入命令
trace com.simonking.boot.tool.controller.TimeController test -n 5 --skipJDKMethod false
运行方法
03 技术选型
耗时的计算用作测试,任意选择都无所谓,只要能达到目的即可。
2.1
到2.3
用作单任务的耗时计算2.4
到2.7
用于复杂 的分段计算,无需不断的创建时间点,只需要重新调用start()方法即可,个别框架apache
调用之前需要reset()
重置之后方可使用。2.8
用于生产问题的定位,可以观察每一段代码的耗时
04 小结
通过合理选择计时方法,可以更准确地获取代码性能数据,帮助优化关键路径逻辑。