Spring Apache and monitor the execution time provided StopWatch

Related Reading

[Small] java home java5 new features (outlined the top ten new features) significant leap
[small] java home java6 new features (outlined the top ten new features) tasteless upgrade
[small] java7 home java new features (outlined eight new characteristics) tepid
[small] java8 home java new features (outlined the top ten new features) from the award winning
[small] java9 home java new features (outlined the top ten new features) mixed
[small] java10 home java new features (outlined the top ten new features) small step iteration
[small] java11 home java new features (outlined eight major new feature) first heavy LTS version


Foreword

The encoding process, we often will want to get a piece of code (a method) execution time, this article will introduce two time monitor (stopwatch) to make your elegant, flexible to deal with this problem.

Java Primal way

In this way the most simple, is best understood, of course, it is the most common: our own writing.
For example: If we want to count a piece of code execution time, and so often to write:

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();   //获取开始时间

        //函数主体代码
        //...

        long endTime = System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间: " + (endTime - startTime) + "ms");
    }

Most of the time we use ms can be expressed, but arguably lack of flexibility. If we want to show to nanoseconds, seconds, or even minutes, we had to deal with their own (the value used to convert ms ~)

Of course, probably to the JDK8future, we can become a little flexible in doing so: can such a deal:

    public static void main(String[] args) {
        Instant start = Instant.now();
        //doSomething();
        Instant end = Instant.now();

        Duration duration = Duration.between(start, end);
        System.out.println("millis = " + duration.toMillis());
    }

This flexibility is stronger than the above number. But there are still some disadvantages: Step slightly complicated, in general is not enough elegance, is not so flexible.
Then this article describes a tool for this problem: StopWatchexecution time monitor. Use it to our statistics program execution time, bring a lot of convenience and elegance.

StopWatchWe need to rely on additional Jar: commons-lang3or spring-core, but both are Jar Java developers will guide and therefore dependent on compatibility can be ignored

StopWatchThere are many open source frameworks provide similar functionality: for example, the Apache commons-lang3, of course, Spring framworkprovide their own, this article will do for this presentation were both ~

Commons-lang3 of StopWatch

ApacheThe task execution monitor function provides rich and powerful (powerful than the Spring), flexibility, follows the classic practical case:

    public static void main(String[] args) throws Exception {
        StopWatch watch = StopWatch.createStarted(); //创建后立即start,常用
        //StopWatch watch = new StopWatch();
        //watch.start();

        Thread.sleep(1000);
        System.out.println("统计从开始到现在运行时间:" + watch.getTime() + "ms"); //1000ms

        Thread.sleep(1000);
        watch.split();
        System.out.println("从start到此刻为止的时间:" + watch.getTime());
        System.out.println("从开始到第一个切入点运行时间:" + watch.getSplitTime()); //2245

        Thread.sleep(1000);
        watch.split();
        System.out.println("从开始到第二个切入点运行时间:" + watch.getSplitTime());

        watch.reset(); //重置后必须使用start方法
        watch.start();
        Thread.sleep(1000);
        System.out.println("重新开始后到当前运行时间是:" + watch.getTime()); //1000

        watch.suspend(); //暂停
        Thread.sleep(6000); //模拟暂停6秒钟

        watch.resume(); //上面suspend,这里要想重新统计,需要恢复一下
        System.out.println("恢复后执行的时间是:" + watch.getTime()); //1000  注意此时这个值还是1000

        watch.stop();
        System.out.println("花费的时间》》" + watch.getTime() + "ms"); //1002ms
        System.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s"); //1s 可以直接转成s

    }

Print Results:

统计从开始到现在运行时间:1007ms
从start到此刻为止的时间:2008
从开始到第一个切入点运行时间:2008
从开始到第二个切入点运行时间:3009
重新开始后到当前运行时间是:1000
恢复后执行的时间是:1000
花费的时间》》1001ms
花费的时间》》1s

As is the StopWatchbasic use, its powerful enough to see it, of course, but also enhance the complexity of the use of some.

The core principle of interpretation

Principle is relatively simple, easy to look at the source at a glance:

// @since 2.0
public class StopWatch {
    // @since 3.5  这个静态方法出现得稍微晚点哦~
    public static StopWatch createStarted() {
        final StopWatch sw = new StopWatch();
        sw.start();
        return sw;
    }

    // 这些成员变量是实现的核心~~~~~~~~~~~~~~
    private State runningState = State.UNSTARTED;
    private SplitState splitState = SplitState.UNSPLIT;
    private long startTime;
    // 思考:为何有了nonaTime这里还得记录一个Millis Time呢???
    // 因为nanoTime只能拿来计算差值(耗时) 但是getStartTime()这个老API还得靠MillsTime~~~
    private long startTimeMillis;
    private long stopTime;
    
    // 可见:start方法可不是能够多次调用的哦~~和状态是有关的
    public void start() {
        if (this.runningState == State.STOPPED) {
            throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
        }
        if (this.runningState != State.UNSTARTED) {
            throw new IllegalStateException("Stopwatch already started. ");
        }
        this.startTime = System.nanoTime();
        this.startTimeMillis = System.currentTimeMillis();
        this.runningState = State.RUNNING;
    }

    // 停表时,最重要的是记录下了stopTime 的值~~~然后标记状态
    public void stop() {
        if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {
            throw new IllegalStateException("Stopwatch is not running. ");
        }
        if (this.runningState == State.RUNNING) {
            this.stopTime = System.nanoTime();
        }
        this.runningState = State.STOPPED;
    }

    // 状态变为非开始状态...
    public void reset() {
        this.runningState = State.UNSTARTED;
        this.splitState = SplitState.UNSPLIT;
    }

    // 暂停:stopTime 也给了一个值
    public void suspend() {
        if (this.runningState != State.RUNNING) {
            throw new IllegalStateException("Stopwatch must be running to suspend. ");
        }
        this.stopTime = System.nanoTime();
        this.runningState = State.SUSPENDED;
    }

    // 这两个方法是获取差值的
    public long getTime() {
        return getNanoTime() / NANO_2_MILLIS;
    }
    // @since 3.5
    public long getTime(final TimeUnit timeUnit) {
        return timeUnit.convert(getNanoTime(), TimeUnit.NANOSECONDS);
    }

    // @since 2.4 老API  这叫获取启动的时间(啥时候启动的)
    public long getStartTime() {
        if (this.runningState == State.UNSTARTED) {
            throw new IllegalStateException("Stopwatch has not been started");
        }
        // System.nanoTime is for elapsed time
        return this.startTimeMillis;
    }
}

We can see the principle is very simple, nothing more than a pause packaging, reply, split functions Well

Details

== getTimeand getSplitTimeso what difference does it make? ==
To illustrate the problem, here we take a look at getNanoTime()and getSplitNanoTime()also:

    public long getNanoTime() {
        if (this.runningState == State.STOPPED || this.runningState == State.SUSPENDED) {
            return this.stopTime - this.startTime;
        } else if (this.runningState == State.UNSTARTED) {
            return 0;
        } else if (this.runningState == State.RUNNING) {
            return System.nanoTime() - this.startTime;
        }
        throw new RuntimeException("Illegal running state has occurred.");
    }

    public long getSplitNanoTime() {
        if (this.splitState != SplitState.SPLIT) {
            throw new IllegalStateException("Stopwatch must be split to get the split time. ");
        }
        return this.stopTime - this.startTime;
    }

we discover:

  • Call getSplit...before the relevant methods, you must first call the Splitmethod

spilit()Source method as follows:

    public void split() {
        if (this.runningState != State.RUNNING) {
            throw new IllegalStateException("Stopwatch is not running. ");
        }
        this.stopTime = System.nanoTime();
        this.splitState = SplitState.SPLIT;
    }

In calling splitthe method, watchthe state changed to SPLIT. And, and, and stopTime set to the current time . So here we are stopTimestopped, this time calling getSplitNanoTime(), returns to the time difference between the start time of the split. Therefore, this method can be inserted to stop stopTime () (a little jump the queue to catch the foot), and finally re-export (first plugged team, last in the output) ~

And getTime()is to take on the current timestamp minus startTime, it is generally not related to the stopTimevalue, and therefore splitTimethe processing time calculation is clearly more flexible , but generally we use getTime()sufficient

Spring's StopWatch

SpringProvided this task monitor, I still quite like to use, because it can help me a colleague monitor multiple tasks, use is also very convenient. Look at a simple use case:

Note: a monitor capable of recording more than one task execution time This feature is very important Oh ~
for example: we can record multi-segment code takes time , and then a one-time print ~

    public static void main(String[] args) throws Exception {
        // 强烈每一个秒表都给一个id,这样查看日志起来能够更加的精确
        // 至于Id 我觉得给UUID是可行的~
        StopWatch sw = new StopWatch(UUID.randomUUID().toString());

        sw.start("起床");
        Thread.sleep(1000);
        System.out.println("当前任务名称:" + sw.currentTaskName());
        sw.stop();

        sw.start("洗漱");
        Thread.sleep(2000);
        System.out.println("当前任务名称:" + sw.currentTaskName());
        sw.stop();

        sw.start("锁门");
        Thread.sleep(500);
        System.out.println("当前任务名称:" + sw.currentTaskName());
        sw.stop();

        System.out.println(sw.prettyPrint()); // 这个方法打印在我们记录日志时是非常友好的  还有百分比的分析哦
        System.out.println(sw.shortSummary());
        System.out.println(sw.currentTaskName()); // stop后它的值为null


        // 最后一个任务的相关信息
        System.out.println(sw.getLastTaskName());
        System.out.println(sw.getLastTaskInfo());

        // 任务总的耗时  如果你想获取到每个任务详情(包括它的任务名、耗时等等)可使用
        System.out.println("所有任务总耗时:" + sw.getTotalTimeMillis());
        System.out.println("任务总数:" + sw.getTaskCount());
        System.out.println("所有任务详情:" + sw.getTaskInfo()); // 拿到所有的任务
    }

print:

当前任务名称:起床
当前任务名称:洗漱
当前任务名称:锁门
StopWatch 'd6ba9412-d551-4ba7-8b0e-1b7ccb42855d': running time (millis) = 3504
-----------------------------------------
ms     %     Task name
-----------------------------------------
01001  029%  起床
02000  057%  洗漱
00503  014%  锁门

StopWatch 'd6ba9412-d551-4ba7-8b0e-1b7ccb42855d': running time (millis) = 3504
null
锁门
org.springframework.util.StopWatch$TaskInfo@2d554825
所有任务总耗时:3504
任务总数:3
所有任务详情:[Lorg.springframework.util.StopWatch$TaskInfo;@68837a77

I personally prefer to use Spring to provide this monitor because it provides prettyPrint()print log can be analyzed in a very intuitive, and I think that multitasking is also provided a little more practical, of course, it is just personal preference ~

At last

In many cases, writing code is an art, and the means of this utility I feel artistic stronger. I hope we can have more good things in the pursuit of the heart, which is especially important for the admission of new knowledge. Before this monitor is recommended here instead of, allowing little friends more flexible analysis of your code -

Knowledge Exchange

若文章格式混乱,可点击: Description link - text link - text link - text link - text link

== The last: If you think this article helpful to you, may wish to point a praise chant. Of course, your circle of friends to share so that more small partners also are seeing 作者本人许可的~==

If interested in technology content can join the group wx exchange: Java高工、架构师3群.
If the group fails two-dimensional code, please add wx number: fsx641385712(or two-dimensional code is scanned beneath wx). And Note: "java入群"the word, will be invited into the group manually

Guess you like

Origin www.cnblogs.com/fangshixiang/p/11261503.html