java,计时三个不同的循环

java, timing three different loops

在阅读必要的 java item45 时,有三个不同的简单循环,如下面的代码所示,带有时序。第一个和第三个是首选。但是当我给他们计时时,

对于 N < 1,000,000:

length of the list: 1000000
sum is: 499999500000
fast method time: 25
sum is: 499999500000
slower method time: 5
sum is: 499999500000
range method time: 21

第二种方法实际上更快,我认为这可能是因为 java 编译器足够聪明,可以用实际数字替换 a.size()。

但是当N变大的时候,第二种方法确实变慢了。我知道这个实验是幼稚的并且是特定于机器的。我想知道当 N 较小时是否有第二种方法优于其他两种方法的解释。 (节目已运行多次)

length of the list: 10000000
sum is: 49999995000000
fast method time: 44
sum is: 49999995000000
slower method time: 48
sum is: 49999995000000
range method time: 37

代码:

public static void main(String [] args){
// test the speed of initialize 1 million elements
// timing two different loops.

// int N = 10000000;
int N = 1000000;
List<Integer> a = new ArrayList<Integer>(); 
for(int i = 0; i < N; ++i){
    a.add(i);
}
System.out.println("length of the list: " + a.size());

long t1 = System.currentTimeMillis();
long sum = 0;
for(int i = 0, n = a.size(); i < n; ++i){
    sum += a.get(i); 
}
long t2 = System.currentTimeMillis();
System.out.println("sum is: " + sum);
System.out.println("fast method time: " + (t2 - t1));

t1 = System.currentTimeMillis();
sum = 0; 
for(int i = 0; i < a.size(); ++i){
    sum += a.get(i); 
}
t2 = System.currentTimeMillis();
System.out.println("sum is: " + sum);
System.out.println("slower method time: " + (t2 - t1));

t1 = System.currentTimeMillis();
sum = 0; 
for(int i: a){
    sum += i; 
}
t2 = System.currentTimeMillis();
System.out.println("sum is: " + sum);
System.out.println("range method time: " + (t2 - t1));

}

我确实得到了和你一样的结果:

length of the list: 1000000
sum is: 499999500000
fast method time: 32
sum is: 499999500000
slower method time: 12
sum is: 499999500000
range method time: 24

所以我用javap -c反汇编了字节码,我看到javac看到N很小的时候没有做任何优化,事实上,没有做任何优化.

因此,我尝试交换前两个语句的顺序,结果如下:

length of the list: 1000000
sum is: 499999500000
slower method time: 30
sum is: 499999500000
fast method time: 8
sum is: 499999500000
range method time: 25

所以这两种方法的区别不在于方法本身,而在于先发生的方法会比较慢。

至于为什么会这样,我还是百思不得其解(可能是延迟加载某些class?hot-code native compilation?)