使用JUnit

时间:2017-05-22 08:15:09

标签: java junit benchmarking stringbuilder stringbuffer

我运行了以下JUnit测试用例,并且能够为Stringbuffer持续获得比StringBuilder更好的性能结果。我确信我在这里遗漏了一些东西,但我找不到为什么StringBufferStringBuilder获得更好速度的原因。

我的测试用例是,

    @Test
    public void stringTest(){

        String s1 = "s1";
        String s2 = "s2";

        for(int i=0;i<=100000;i++){
            s1 = s1+s2;
        }
        System.out.println(s1);
    }

    @Test
    public void stringBuilderTest(){

        StringBuilder s1 = new StringBuilder("s1");
        String s2 = "s2";

        for(int i=0;i<=100000;i++){
            s1.append(s2);
        }
        System.out.println(s1);
    }


    @Test
    public void stringBufferTest(){

        StringBuffer s1 = new StringBuffer("s1");
        String s2 = "s2";

        for(int i=0;i<=100000;i++){
            s1.append(s2);
        }
        System.out.println(s1);
    }

请查找JUnit测试结果

JUnit Test 1 JUnit Test 2

正如您在上面的结果{$ 1}}中看到的那样,案件的执行速度早于stringBufferTest。我的问题是为什么会这样?我知道这在理论上是不可能的,但我是如何得到这个结果的?

更新

根据@ Henry的评论,我删除了SysOuts,结果发生了巨大变化。

JUnit Test 3 - removing the SysOut

然后我将循环次数增加100000 - &gt; 1000000并且能够得到一些我一直期待的真实结果,

JUnit Test 3 - removing the SysOut for 1000000 iterations

我的新问题是,

  1. 当我删除我的时,为什么我的性能会有显着提升 SYSOUT?
  2. 当负载在1000000 StringBuffer给出时从低到高增加 比StringBuilder最好的结果,为什么会这样?

1 个答案:

答案 0 :(得分:2)

我担心您的基准测试基本无效。

Microbenchmarks(小代码,相对较快地完成)很难用Java(以及许多其他语言)来实现。使这些基准难以解决的一些问题:

  • 根据测试的编写方式,编译器可能会优化一些代码,导致基准不能测量您想要测量的内容。
  • 在运行时(而不是编译时)发生的优化通常会逐步发生。最初,代码被解释。只有当它的某些部分经常执行时,Just in Time编译器才会生成优化的机器代码。微量标记通常不会触发此优化。 http://www.oracle.com/technetwork/java/whitepaper-135217.html有关此主题的更多信息。
  • 即使代码符合优化条件,根据其编写方式,即时编译器可能无法完全修补它,因此它必须回退到次优优化。搜索“堆栈更换”以获取更多详细信息。

Oracle的这篇文章详细介绍了这些问题:http://www.oracle.com/technetwork/articles/java/architect-benchmarking-2266277.html

最后,归结为:除非你对此非常有经验,否则不要从头开始编写微基准。您获得的结果与该代码在实际应用程序中的执行方式无关。

使用类似JMH(Java Microbenchmark Harness)的框架。我上面链接的文章包含JMH的介绍,但也有其他教程(例如http://java-performance.info/jmh/)。

投入一些时间学习使用JMH。这很值得。当您使用JMH运行基准测试时,您将在其输出中看到基准时间由于JVM优化而发生的变化(JMH多次调用您的测试)。

如果在JMH中运行StringBuilder与StringBuffer测试,您应该会发现两个类在现代CPU上的执行情况大致相同。 StringBuilder稍微快一点,但不是那么多。不过,我会使用StringBuilder,因为它稍快一些。