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() 会显示所有同名任务的耗时)。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐