计时这个词语在生活中被应用的很普遍,体育竞赛时频繁出现的秒表,发令信号一经发出,秒表就在滴答滴答流转开始计时了,秒表此时的作用就是计时的代名词,在我们编写代码的时候,时不时也要统计一下执行一个方法或者一系列逻辑时所消耗的时间。
这时我们就用到了java常用的计时方式之一了,System.currentTime()方法在方法的前后计算时间差。配上代码的方式我们来看下。
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
final long size = 1000000000;
long sum = 0;
for (int i = 0; i < size; i++) {
sum += i;
}
long endTime = System.currentTimeMillis();
System.out.println("统计计算0~1000000000相加的总和" + sum + "耗时时间为:" + (endTime - startTime) + "ms");
}
我们先分析这段代码涉及的内容吧,计算0到1000000000之间数字的总和,进行统计所消耗的时间,进行手动输出。
public static native long currentTimeMillis();
上面的方法使用native关键字进行标识,这不是一个java方法,而是一个本地方法,本地方法是运行在本地方法栈的。
想了解本地方法栈和java方法栈的内容可以先看下这两篇文章java虚拟机,应该了解一点点,另外一篇是java内存区域划分详解,后面的一篇是对前面内容的详细描述吧,希望可以帮助到你,喜欢的可以关注此公众号,转发,分享一下。
我们继续说下另外一种计时方法吧,StopWatch,这是spring框架提供的一个工具类,只要你使用了spring框架,就无需导入其它jar包了,好了,我们看下它的常见用法吧,继续按照我们一贯的风格,先将代码看下。
public static void main(String[] args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start("统计0~1000000000相加的总和所需时间");
final long size = 1000000000;
long sum = 0;
for (int i = 0; i < size; i++) {
sum += i;
}
stopWatch.stop();
//下面我们使用stopWatch提供的方法进行信息的输出
System.out.println(stopWatch.prettyPrint());
}
StopWatch的使用,先手动new一个对象,通过这个对象我们可以调用里面的实例方法了。
下面我们继续看下StopWatch工具类提供的常用方法吧
我们看下stopWatch方法做了什么,和原来的有什么不一样的,除了多了给当前的执行
任务起了一个有明确含义的任务名,在计算时间时任然时调用的是System.currentTimeMillis()方法
public void start(String taskName) throws IllegalStateException {
if (this.currentTaskName != null) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
} else {
this.currentTaskName = taskName;
this.startTimeMillis = System.currentTimeMillis();
}
}
好了,上面的方法,大致上你应该明白其中的含义了,下面我们看下StopWatch是如何帮我们计算时间差的stop方法吧,我们继续看下下面的代码咯。
首先你在new StopWatch()对象时可以设置taskName,不过我们设置名字建议要设置
一个有意义的名字,不然后续出现问题时,定位问题很麻烦,其实stop()方法
在内部也是按照传统的计算时间差的方法,看下int lastTime=System.currentTimeMillis() - this.startTimeMillis;
和我们自己设置没什么两样。
public void stop() throws IllegalStateException {
if (this.currentTaskName == null) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
} else {
long lastTime = System.currentTimeMillis() - this.startTimeMillis;
this.totalTimeMillis += lastTime;
this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName, lastTime);
if (this.keepTaskList) {
this.taskList.add(this.lastTaskInfo);
}
++this.taskCount;
this.currentTaskName = null;
}
}
上面的代码的第11行通过stopWatch实例new了一个taskInfo对象,我们看下这个静态内部类的代码吧,go on。
public static final class TaskInfo {
private final String taskName;
private final long timeMillis;
TaskInfo(String taskName, long timeMillis) {
this.taskName = taskName;
this.timeMillis = timeMillis;
}
public String getTaskName() {
return this.taskName;
}
public long getTimeMillis() {
return this.timeMillis;
}
public double getTimeSeconds() {
return (double)this.timeMillis / 1000.0D;
}
}
这个静态内部类的主要作用是记录当前任务的名称和时间的,将其封装成一个对象,为下面的流程做下铺垫的。
在stop()方法的代码里面第13行将taskInfo对象信息装入的集合中,这样当有多个任务时,我们打印任务集合信息时就可以了,很方便。
下面再分析一下这个方法了,在我们的示例中,我们使用了下面的这个方法prettyPrint()进行信息格式友好的输出。
public String shortSummary() {
return "StopWatch '" + this.getId() + "': running time (millis) = " + this.getTotalTimeMillis();
}
public String prettyPrint() {
//调用上面的方法,在信息头部输出计时所耗时间
StringBuilder sb = new StringBuilder(this.shortSummary());
//使用StringBuilder进行字符串信息的拼接
sb.append('\n');
if (!this.keepTaskList) {
sb.append("No task info kept");
} else {
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);
//下面就是将你的程序写入的任务信息进行输出
StopWatch.TaskInfo[] var4 = this.getTaskInfo();
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
StopWatch.TaskInfo task = var4[var6];
sb.append(nf.format(task.getTimeMillis())).append(" ");
sb.append(pf.format(task.getTimeSeconds() / this.getTotalTimeSeconds())).append(" ");
sb.append(task.getTaskName()).append("\n");
}
}
return sb.toString();
}
StopWatch的内容到这里就讲完了,整个流程大致上就是常用方法的使用了。