咱们常常须要统计一个办法的耗时,个别咱们会这样做:

public class Test {    public static void main(String[] args) throws InterruptedException {        long start = System.currentTimeMillis();        // 睡眠100ms,模仿工作耗时        Thread.sleep(100L);        long end = System.currentTimeMillis();        System.out.println("耗时:" + (end - start)); // 输入 耗时:104    }}

这样做尽管简略间接,当咱们须要分段统计耗时的时候,一不留神就找不到开始工夫在哪了。而且也不能汇总后果,不能直观的看到每一步的耗时。

有一个简略的小工具,能够帮忙咱们非常容易的统计办法耗时。

名字叫StopWatch,在常见的类库,例如Spring、Apache Commons、Google Guava都有这个工具,性能和实现都是大同小异,举荐应用Spring里的,能够更不便统计耗时的汇总后果。

把耗时代码换成StopWatch试一下:

public class Test {    public static void main(String[] args) throws InterruptedException {        // 创立统计工作        StopWatch stopWatch = new StopWatch();        // 开始计时        stopWatch.start();        // 睡眠100ms,模仿工作耗时        Thread.sleep(100L);        // 完结计时        stopWatch.stop();        // 打印统计后果        System.out.println(stopWatch.prettyPrint());    }}

输入后果是:

StopWatch '': running time (millis) = 104-----------------------------------------ms     %     Task name-----------------------------------------00104  100%  

只统计了一个工作的耗时,还不能展现出StopWatch劣势,上面一次统计多个工作的耗时:

public class CopyTest {    public static void main(String[] args) {        // 创立统计工作,并指定ID        StopWatch stopWatch = new StopWatch("Main办法耗时");        IntStream.rangeClosed(1, 10).forEach(index -> {            // 开始计时,并指定工作名称,便于展现            stopWatch.start("task" + index);            // 睡眠100ms,模仿工作耗时            try {                Thread.sleep(100L);            } catch (InterruptedException e) {            }            // 完结计时            stopWatch.stop();        });        // 打印统计后果        System.out.println(stopWatch.prettyPrint());    }}

输入后果是:

StopWatch 'Main办法耗时': running time (millis) = 1039-----------------------------------------ms     %     Task name-----------------------------------------00103  010%  task100107  010%  task200104  010%  task300104  010%  task400105  010%  task500102  010%  task600104  010%  task700102  010%  task800105  010%  task900103  010%  task10

打印出了每个工作的耗时,并统计了在总耗时所占百分比,曾经十分直观了。

这是怎么实现的呢?其实源码非常简单,就用一个LinkedList记录了每个工作的耗时:

public class StopWatch {    // 总任务ID    private final String id;    // 工作汇合    private final List<TaskInfo> taskList = new LinkedList<TaskInfo>();    private long startTimeMillis;    private boolean running;    private String currentTaskName;    private TaskInfo lastTaskInfo;    private long totalTimeMillis;    public StopWatch() {        this("");    }    public StopWatch(String id) {        this.id = id;    }    public void start() throws IllegalStateException {        start("");    }    // 开始计时,并记录开始工夫    public void start(String taskName) throws IllegalStateException {        if (this.running) {            throw new IllegalStateException("Can't start StopWatch: it's already running");        }        this.running = true;        this.currentTaskName = taskName;        this.startTimeMillis = System.currentTimeMillis();    }    // 完结计时,统计耗时,并增加到taskList外面    public void stop() throws IllegalStateException {        if (!this.running) {            throw new IllegalStateException("Can't stop StopWatch: it's not running");        }        long lastTime = System.currentTimeMillis() - this.startTimeMillis;        this.totalTimeMillis += lastTime;        this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);        this.taskList.add(lastTaskInfo);        this.running = false;        this.currentTaskName = null;    }    public long getLastTaskTimeMillis() throws IllegalStateException {        if (this.lastTaskInfo == null) {            throw new IllegalStateException("No tasks run: can't get last task interval");        }        return this.lastTaskInfo.getTimeMillis();    }    public String getLastTaskName() throws IllegalStateException {        if (this.lastTaskInfo == null) {            throw new IllegalStateException("No tasks run: can't get last task name");        }        return this.lastTaskInfo.getTaskName();    }    public double getTotalTimeSeconds() {        return this.totalTimeMillis / 1000.0;    }    public TaskInfo[] getTaskInfo() {        return this.taskList.toArray(new TaskInfo[this.taskList.size()]);    }    public String shortSummary() {        return "StopWatch '" + getId() + "': running time (millis) = " + getTotalTimeMillis();    }        // 打印统计后果    public String prettyPrint() {        StringBuilder sb = new StringBuilder(shortSummary());        sb.append('\n');        sb.append("-----------------------------------------\n");        sb.append("ms     %     Task name\n");        sb.append("-----------------------------------------\n");        NumberFormat nf = NumberFormat.getNumberInstance();        nf.setMinimumIntegerDigits(5);        nf.setGroupingUsed(false);        NumberFormat pf = NumberFormat.getPercentInstance();        pf.setMinimumIntegerDigits(3);        pf.setGroupingUsed(false);        for (TaskInfo task : getTaskInfo()) {            sb.append(nf.format(task.getTimeMillis())).append("  ");            sb.append(pf.format(task.getTimeSeconds() / getTotalTimeSeconds())).append("  ");            sb.append(task.getTaskName()).append("\n");        }        return sb.toString();    }    public static final class TaskInfo {        private final String taskName;        private final long timeMillis;        TaskInfo(String taskName, long timeMillis) {            this.taskName = taskName;            this.timeMillis = timeMillis;        }    }}

感觉怎么样?连忙应用起来吧。