日期:2014-05-20  浏览次数:20669 次

阿里巴巴2014笔试题,速来围观!!!
问下面哪个方法计算速度更快


public class FFFtest {
public static void main(String[] args) {
int[] a=new int[1000];
int[] b=new int[10000000];
long start = System.currentTimeMillis();
//method 1
for(int i=0;i<1000;i++){
for(int j=0;j<10000000;j++){
a[i]++;
}
}
long end = System.currentTimeMillis();
System.out.println(end-start);

start=System.currentTimeMillis();
//method 2
for(int i=0 ;i<10000000;i++){
for(int j=0;j<1000;j++){
b[i]++;
}
}
end = System.currentTimeMillis();
System.out.println(end-start);


}
}

输出:
25616
21736

结果表示,第二中更快一些,求解释!!!
阿里巴巴 java

------解决方案--------------------
测试1:将赋值语句注释 
 public static void main(String[] args) {
        int[] a=new int[1000];
        int[] b=new int[10000000];
        long start = System.currentTimeMillis();
        //method 1
        for(int i=0;i<1000;i++){
            for(int j=0;j<10000000;j++){
//                a[i]++;
            }
        }
        long end = System.currentTimeMillis();
        System.out.print(end-start+"\t");
         
        start=System.currentTimeMillis();
        //method 2
        for(int i=0 ;i<10000000;i++){
            for(int j=0;j<1000;j++){
//                b[i]++;
            }
        }
        end = System.currentTimeMillis();
        System.out.println(end-start);

    }

测试结果:
3704    4095
3625 3860
3609 3877
3609 4001


测试2:恢复赋值(同楼主代码)
测试结果:
23616 22096
23048 21986
24164 22495
23532 22175

结果分析:
1、通过测试1(仅循环切换耗时)可以证明6楼的所说,第一段代码从内层循环切到外层的次数为 1000次;第二段代码从内层循环切到外层的次数为10000000次,所以切换多的耗时多

2、通过测试2看到加上赋值后第一段代码明显耗时明显增加,两段代码赋值次数都一样,但是第一段代码每一个数组元素都是从1-10000000赋值,存大赋值大数据

所以我觉得整体来说大赋值大数据耗时会比较多
------解决方案--------------------
这题的理性认识应该是第一个比较快。 
因为a[i]和b[i]都是一个内存查找的动作,而a[i]只查找了1000次,b[i]却查找了10000000次。a[i]更多地击中了CPU的缓存(快),而b[i]更多地进行了内存查找(慢)。

于是乎这就是一个micro benchmark的问题了。Java的micro benchmark是很难的,也没有什么绝对公平的方法。难点在于JVM的JIT。

对于进行micro benchmark的方法,首先要进行预热,其次要进行统计。
预热的概念是让JVM先行运行该方法若干次(关键词:compile threshold),使其JIT对方法进行优化和编译。
统计的意思是运行多次测试,取平均值、中值、标准差等数据进行综合比较。
另外要注意的一点是,绝对不能在同一个程序里面测试两种方法。要编译测试两个方法的不同版本分别进行测试,否则会有干扰。

以下是我的测试方法:这个测试里面我没有用统计方法,因为结果已经很明显了:方法一比方法二快了2.5倍左右

package test;

public class Test {

  static int[] a = new int[100];
  static int[] b = new int[100000];

  public static void main(final String[] args) throws Exception {

    // warm up
    for (int i = 0; i < 5000; i++)
      method2();

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++)
      method2();
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }

  static void method1() {
    for (int i = 0; i < 100; i++) {
      for (int j = 0; j < 100000; j++) {
        a[i]++;
      }