性能分析工具-StopWatch
1 前言
在开发过程中,统计代码段的执行耗时是定位性能瓶颈、验证优化效果的重要手段。StopWatch是一个轻量级计时工具,能够简洁、直观地完成这一任务。以下主要是介绍Spring框架提供的StopWatch为例(最常用且功能完善),详细讲解使用方法。
2 什么是StopWatch
StopWatch是一个用于计时和统计代码执行耗时的工具类,主要功能包括:
分段计时:支持统计多个任务的耗时(如用户登录流程中的密码验证、权限加载等);
自动累加总耗时:无需手动计算个任务耗时之和;
格式化输出:可直接输出包含各任务耗时占比的易读结果;
轻量无侵入:仅需少量代码即可集成,适合调试和性能分析
3 核心功能与优势
| 功能特性 | 说明 |
| 分段计时 | 支持标记多个任务的起止时间,分别统计耗时。 |
| 自动总耗时计算 | 自动累加所有任务的耗时,直接获取总耗时(毫秒/秒)。 |
| 格式化输出 | 自动累加所有任务的耗时,直接获取总耗时(毫秒/秒) |
| 线程安全(单线程内) | 通过 prettyPrint() 输出各任务耗时及占比,直观易懂。 |
| 线程安全(单线程内) | 非线程安全,需在单线程内使用(避免多线程共享实例导致计时混乱) |
4 基础使用:单任务计时
4.1 基本流程
使用StopWatch的核心步骤:
1、创建StopWatch实例(可选指定标识ID)
2、调用start()开始计时(需传入任务名称)
3、执行目标代码段(如数据库查询、接口调用等)
4、调用stop()停止计时
5、获取统计结果(总耗时 、各任务详情等)
4.2 示例
import org.springframework.util.StopWatch;
public class Test {
public static void main(String[] args) throws InterruptedException {
// 1、创建StopWatch示例
StopWatch stopWatch = new StopWatch("示例:单任务计时性能分析");
// 2、开始计时
stopWatch.start("任务1:模拟RPC调用接口获取数据");
// 3、执行目标代码,休眠1秒(模拟查询耗时)
Thread.sleep(1000);
// 4、停止计时
stopWatch.stop();
// 5、输出结果
System.out.println("总耗时(毫秒):" + stopWatch.getTotalTimeMillis());
System.out.println("总耗时(秒):" + stopWatch.getTotalTimeSeconds());
System.out.println("详细信息:\n" + stopWatch.prettyPrint());
}
}
4.3 结果
总耗时(毫秒):1009
总耗时(秒):1.009
详细信息:
StopWatch '示例:单任务计时性能分析': running time (millis) = 1009
-----------------------------------------
ms % Task name
-----------------------------------------
01009 100% 任务1:模拟RPC调用接口获取数据
5 进阶使用:多任务分段计时
5.1 基本流程
实际开发过程中,一般需要统计多个任务的耗时。StopWatch支持多次调用start()和stop()来分段计时,并自动累加总耗时。
5.2 示例
import org.springframework.util.StopWatch;
public class Test {
public static void main(String[] args) throws InterruptedException {
// 1、创建StopWatch示例
StopWatch stopWatch = new StopWatch("示例:多任务计时性能分析");
// 任务1:验证用户名密码
stopWatch.start("任务1:验证用户名密码");
// 模拟验证耗时 300ms
Thread.sleep(300);
stopWatch.stop();
// 任务2:加载用户权限
stopWatch.start("任务2:加载用户权限");
// 模拟验证耗时 500ms
Thread.sleep(500);
stopWatch.stop();
// 任务3:生成登录日志
stopWatch.start("任务3:生成登录日志");
// 模拟验证耗时 200ms
Thread.sleep(200);
stopWatch.stop();
// 5、输出结果
System.out.println("总耗时(毫秒):" + stopWatch.getTotalTimeMillis());
System.out.println("总耗时(秒):" + stopWatch.getTotalTimeSeconds());
System.out.println("详细信息:\n" + stopWatch.prettyPrint());
}
}
5.3 结果
总耗时(毫秒):1033
总耗时(秒):1.033
详细信息:
StopWatch '示例:多任务计时性能分析': running time (millis) = 1033
-----------------------------------------
ms % Task name
-----------------------------------------
00309 030% 任务1:验证用户名密码
00512 050% 任务2:加载用户权限
00212 021% 任务3:生成登录日志
6 循环场景:批量操作计时
6.1 基本流程
在批量处理场景中,StopWatch可快速统计总耗时,甚至单个循环的平均耗时
6.2 示例
import org.springframework.util.StopWatch;
public class Test {
public static void main(String[] args) throws InterruptedException {
// 创建StopWatch示例
StopWatch stopWatch = new StopWatch("示例:批量数据处理耗时统计");
for (int i=0; i<10; i++) {
stopWatch.start("第" + (i+1) + "条数据");
// 模拟单条数据执行时间
Thread.sleep((i+1));
stopWatch.stop();
}
// 输出结果
System.out.println("总耗时(毫秒):" + stopWatch.getTotalTimeMillis());
System.out.println("总耗时(秒):" + stopWatch.getTotalTimeSeconds());
System.out.println("详细信息:\n" + stopWatch.prettyPrint());
}
}
6.3 结果
总耗时(毫秒):69
总耗时(秒):0.069
详细信息:
StopWatch '示例:批量数据处理耗时统计': running time (millis) = 69
-----------------------------------------
ms % Task name
-----------------------------------------
00002 003% 第1条数据
00002 003% 第2条数据
00005 007% 第3条数据
00005 007% 第4条数据
00005 007% 第5条数据
00006 009% 第6条数据
00008 012% 第7条数据
00008 012% 第8条数据
00009 013% 第9条数据
00019 028% 第10条数据
7 核心方法详解
StopWatch的核心方法如下表所示:
| 方法 | 说明 |
| StopWatch() | 无参构造,创建无 ID 的实例 |
| StopWatch(String id) | 带 ID 的构造,用于区分不同统计场景(prettyPrint() 会显示 ID)。 |
| void start(String taskName) | 开始计时(需传入任务名称,用于标识当前任务)。 |
| void stop() | 停止当前任务计时(必须与 start() 配对使用,否则抛异常)。 |
| long getTotalTimeMillis() | 返回所有任务的总耗时(毫秒) |
| double getTotalTimeSeconds() | 返回所有任务的总耗时(秒,浮点型)。 |
| String prettyPrint() | 格式化输出所有任务的耗时详情(含各任务耗时占比)。 |
| TaskInfo[] getTaskInfo() | 返回所有任务的 TaskInfo 数组(包含任务名称和耗时) |
| boolean isRunning() | 判断当前是否有任务正在计时(start() 后未 stop()) |
8 注意事项
8.1 必须配对使用start()和stop()
每次调用start()后,必须调用stop()停止当前任务计时,否则会导致:
后续start()调用抛出IllegalStateException(因前一个任务未停止)
总耗时统计错误(未停止的任务会持续计时)
8.2 单线程内使用
StopWatch 是非线程安全的工具类,不能在多线程中共享实例(如多个线程同时调用 start() 会导致计时混乱)。每个线程需独立创建 StopWatch 实例。
8.3 避免嵌套计时
不支持在一个未停止的任务中调用 start()(即不能嵌套计时),否则会抛异常。
8.4 任务名称可重复
任务名称仅用于标识,允许重复(prettyPrint() 会显示所有同名任务的耗时)。
更多推荐
所有评论(0)