记录JAVA代码执行耗时工具及示例

参考文章:https://mp.weixin.qq.com/s/Oi0TWbsGUDpl-6lZHIYrKg

一、功能说明及效果展示

1. 支持多任务计时,每个子任务多段计时

2. 效果展示:

/** 
* 四种统计方案:
*  时间差统计
*  StopWatchTool
*  Function
*  AutoCloseable
*/
System:
 51
101
test StopWatchTool:
-----------------------------------------
taskName   taskChildName    ms 
-----------------------------------------
set : set  first  52  
get : get  first  51  

test Function:
-----------------------------------------
taskName   taskChildName    ms 
-----------------------------------------
set : set  first  50  second  50  
get : get  first  50  second  50  

test AutoCloseable:
-----------------------------------------
taskName   taskChildName    ms 
-----------------------------------------
set : set  first  51  second  52  
get : get  first  50  second  51 

二、实现方式

1. 计时工具:StopWatchTool

2. 包装计时器:StopWatchHolder,为了支持function调用

三、测试代码

/** 
* 四种统计方案:
*  时间差统计
*  StopWatchTool
*  Function
*  AutoCloseable
*/
public static void main(String[] args) throws InterruptedException {

    //时间差统计
    Long start = System.currentTimeMillis();

    Thread.sleep(50);

    Long end1 = System.currentTimeMillis();

    Thread.sleep(50);

    Long end2 = System.currentTimeMillis();

    System.out.println((end1 - start));
    System.out.println((end2 - start));

    //StopWatchTool
    StopWatchTool stopWatch = StopWatchTool.newInstance("test StopWatchTool");

    stopWatch.start("set", "first");
    Thread.sleep(50);

    stopWatch.stop();
    stopWatch.start("get", "first");

    Thread.sleep(50);

    stopWatch.stop();
    System.out.println(stopWatch.prettyPrint());

    //Function
    stopWatch = StopWatchTool.newInstance("test Function");

    StopWatchHolder.run(stopWatch, "set", "first", s -> {
        try {
            Thread.sleep(50);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
    
    //同一个任务,两段计时
    StopWatchHolder.run(stopWatch, "set", "second", s -> {
        try {
            Thread.sleep(50);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });

    StopWatchHolder.run(stopWatch, "get", "first", g -> {
        try {
            Thread.sleep(50);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
    
    //同一个任务,两段计时
    StopWatchHolder.run(stopWatch, "get", "second", g -> {
        try {
            Thread.sleep(50);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });

    System.out.println(stopWatch.prettyPrint());

    //AutoCloseable
    stopWatch = StopWatchTool.newInstance("test AutoCloseable");

    try(StopWatchTool ignored = stopWatch.startByChain("set", "first")) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    try(StopWatchTool ignored = stopWatch.startByChain("set", "second")) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    try(StopWatchTool ignored = stopWatch.startByChain("get", "first")) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    try(StopWatchTool ignored = stopWatch.startByChain("get", "second")) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    System.out.println(stopWatch.prettyPrint());
}

四、源代码

public class StopWatchHolder {

    /**
     * 有返回值调用
     */
    public static <T> T run(StopWatchTool stopWatch, String taskName, String taskChildName, Supplier<T> supplier) {
        try {
            stopWatch.start(taskName, taskChildName);

            return supplier.get();
        } finally {
            stopWatch.stop();
        }
    }

    /**
     * 无返回值调用
     */
    public static void run(StopWatchTool stopWatch, String taskName, String taskChildName, IntConsumer function) {
        try {
            stopWatch.start(taskName, taskChildName);

            function.accept(0);
        } finally {
            stopWatch.stop();
        }
    }
}
public class StopWatchTool implements AutoCloseable {

    /**
     * 任务ID
     */
    private String id;

    /**
     * Start time of the current task.
     */
    private long startMs;

    /**
     * Name of the current task.
     */
    @Nullable
    private String currentTaskName;

    /**
     * Second Name of the current task.
     */
    @Nullable
    private String currentTaskChildName;

    //记录任务信息,同一任务,可以分段计时
    private final Map<String, List<TaskInfo>> taskMap = new HashMap<>();

    public static StopWatchTool newInstance(String id) {
        return new StopWatchTool(id);
    }

    @Override
    public void close() {
        this.stop();
    }


    public StopWatchTool(String id) {
        this.id = id;
    }

    /**
     * 开始时间差类型指标记录,如果需要终止,请调用 {@link #stop()}
     *
     * @param taskName 指标名
     */
    public void start(String taskName, String taskChildName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatchTool: it's already running");
        }
        this.currentTaskName = taskName;
        this.currentTaskChildName = taskChildName;
        this.startMs = System.currentTimeMillis();
    }

    /**
     * 返回this,支持链式调用
     *
     * @param taskName
     * @return
     * @throws IllegalStateException
     */
    public StopWatchTool startByChain(String taskName, String taskChildName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatchTool: it's already running");
        }
        this.currentTaskName = taskName;
        this.currentTaskChildName = taskChildName;
        this.startMs = System.currentTimeMillis();

        return this;
    }

    /**
     * 终止时间差类型指标记录,调用前请确保已经调用
     */
    public void stop() throws IllegalStateException {
        if (this.currentTaskName == null) {
            throw new IllegalStateException("Can't stop TraceWatch: it's not running");
        }
        long lastTime = System.currentTimeMillis() - this.startMs;

        TaskInfo info = new TaskInfo(this.currentTaskName, this.currentTaskChildName, lastTime);

        this.taskMap.computeIfAbsent(this.currentTaskName, e -> new LinkedList<>()).add(info);

        this.currentTaskName = null;
    }

    /**
     * 直接记录指标数据,不局限于时间差类型
     *
     * @param taskName 指标名
     * @param data     指标数据
     */
    public void record(String taskName, String taskChildName, Object data) {

        TaskInfo info = new TaskInfo(taskName, taskChildName, data);

        this.taskMap.computeIfAbsent(taskName, e -> new LinkedList<>()).add(info);
    }

    /**
     * 打印
     *
     * @return
     */
    public String prettyPrint() {
        String whiteStr = "  ";
        StringBuilder sb = new StringBuilder(id).append(":").append("\n");

        if (this.taskMap.isEmpty()) {
            sb.append("No task info kept");
        } else {
            sb.append("-----------------------------------------\n");
            sb.append("taskName   taskChildName    ms \n");
            sb.append("-----------------------------------------\n");

            for (Map.Entry<String, List<TaskInfo>> entry : taskMap.entrySet()) {
                sb.append(entry.getKey());
                sb.append(" : ");
                for (int i = 0; i < entry.getValue().size(); i++) {
                    TaskInfo taskInfo = entry.getValue().get(i);
                    if (i == 0) {
                        sb.append(taskInfo.getTaskName()).append(whiteStr);
                    }
                    sb.append(taskInfo.getTaskChildName()).append(whiteStr);
                    sb.append(taskInfo.getData()).append(whiteStr);
                }
                sb.append("\n");
            }
        }

        return sb.toString();
    }


    /**
     * 任务信息
     */
    public static final class TaskInfo {

        private final String taskName;

        private final String taskChildName;

        private final Object data;

        public TaskInfo(String taskName, String taskChildName, Object data) {
            this.taskName = taskName;
            this.taskChildName = taskChildName;
            this.data = data;
        }

        public String getTaskName() {
            return taskName;
        }

        public String getTaskChildName() {
            return taskChildName;
        }

        public Object getData() {
            return data;
        }
    }
}