6

下面的代码证明了method1比method2快。任何人都可以评论这种行为的原因是什么。

class Trial {
        String _member;
        void method1() {
            for(int i=0;i<30480;i++) {
                _member += "test";
            }
        }
        void method2() {
            String temp="";
            for(int i=0;i<30480;i++) {
                temp += "test";
            }
            _member = temp;
        }

        public static void main(String args[]) {
            Trial t = new Trial();
            long startTime1 = System.currentTimeMillis();
            t.method1();
            long endTime1 = System.currentTimeMillis();
            long startTime2 = System.currentTimeMillis();
            t.method2();
            long endTime2 = System.currentTimeMillis();
            System.out.println(endTime1 - startTime1);
            System.out.println(endTime2 - startTime2);
        }
    }
4

3 回答 3

12

下面的代码证明method1比method2快

不,它不能证明这一点。

这取决于许多因素。当我运行这段代码时,我得到

1403
1248

因此,在我的环境中,您的代码“证明”method1比 method2慢。

在进行基准测试时,您需要注意缓存和 JVM 预热等效果。

也可以看看

了解更多信息。


我稍微重构了main方法:

...

static void doBenchmark() {
   Trial t = new Trial();

   long startTime1 = System.currentTimeMillis();
   t.method1();
   long endTime1 = System.currentTimeMillis();

   long startTime2 = System.currentTimeMillis();
   t.method2();
   long endTime2 = System.currentTimeMillis();

   System.out.println(endTime1 - startTime1);
   System.out.println(endTime2 - startTime2);
}

public static void main(String args[]) {

   for (int i = 0;  i < 20;  i++) {
      doBenchmark();
      System.out.println("----");
   }
}

这导致 -loop 的第一次迭代的值相似for随后结果收敛并且不再有显着差异:

1396
1133
----
1052
1070
----
688
711
----
728
726
----
715
709
----
...

甚至,有时method1似乎更快,有时method2——这很可能是由于测量不准确。

于 2013-06-18T07:19:23.983 回答
0

我已经修改了测试的数量,但没有修改方法,这里使用StringBuilder 2500 在 3000时更快!

class Trial {
    StringBuilder _member = new StringBuilder(243840);
    void method1() {
        for (int i = 0; i < 30480; i++) {
            _member.append("test");
        }
    }

    void method2() {
        final StringBuilder temp = new StringBuilder(243840);
        for (int i = 0; i < 30480; i++) {
            temp.append("test");
        }
        _member = temp;
    }
    public static void main(final String args[]) {
        long startTime1 = System.nanoTime();
        new Trial().method1();
        long endTime1 = System.nanoTime();
        long startTime2 = System.nanoTime();
        new Trial().method2();
        long endTime2 = System.nanoTime();
        System.out.println(endTime1 - startTime1);
        System.out.println(endTime2 - startTime2);
        System.out.println("------------------");
        startTime1 = System.nanoTime();
        new Trial().method1();
        endTime1 = System.nanoTime();
        startTime2 = System.nanoTime();
        new Trial().method2();
        endTime2 = System.nanoTime();
        System.out.println(endTime1 - startTime1);
        System.out.println(endTime2 - startTime2);
    }
}

输出:

method1 then method2 with += in MILLIisecond
5563
5844
............................................
5437
6344

method2 then method1 with += in MILLIisecond
4625
5969
------------------
6531
4891

=====================================================

method1 then method2 with StringBuilder in NANOsecond
3530337
2074286
------------------
2058641
1983493
.....................................................

method2 then method1 with StringBuilder in NANOsecond
3430883
1698819
------------------
2065626
2144406

所以正如@Andreas 所说,这不是测试性能的好方法。

需要指出的一点:使用声明大小的StringBuilder(在 Joshua Bloch 的书 Effective Java Item 51: Beware the performance of string concatenation 中
-尽可能选择 method2(): String[Builder] 在里面声明,而不是在外面使用

于 2013-06-18T07:58:59.667 回答
0

预热 jvm 一段时间后,您会看到method2 比 method1 快

这是我重构的代码:

class Trial {
String _member;

  void method1() {
    for (int i = 0; i < 30480; i++) {
        _member += "test";
    }
  }

  void method2() {
    String temp = "";
    for (int i = 0; i < 30480; i++) {
        temp += "test";
    }
    _member = temp;
  }

  public static void main(String args[]) {
    Trial t = new Trial();

    for (int i = 0; i < 10; i++) { //warm up jvm
        t.method1();
        t.method2();
    }

    t = new Trial();

    long startTime1 = System.currentTimeMillis();
    t.method1();
    long endTime1 = System.currentTimeMillis();
    long startTime2 = System.currentTimeMillis();
    t.method2();
    long endTime2 = System.currentTimeMillis();
    System.out.println(endTime1 - startTime1);
    System.out.println(endTime2 - startTime2);
  }
}

结果如下:

----
2910
2894
----

但是对于实际的基准测试,你应该运行它几次并观察统计行为,然后你才能得出任何结论!

于 2013-06-18T07:40:49.230 回答