StringBuffer和StringBuilder之间的主要区别是什么?在决定其中任何一项时是否存在性能问题?


当前回答

StringBuffer已同步,StringBuilder未同步。

其他回答

字符串缓冲区:

多线程已同步比StringBuilder慢

字符串拼接

单线程未同步比以往更快的字符串

在单线程中,由于JVM的优化,StringBuffer不会比StringBuilder慢很多。在多线程中,不能安全地使用StringBuilder。

这是我的测试(不是基准测试,只是测试):

public static void main(String[] args) {

    String withString ="";
    long t0 = System.currentTimeMillis();
    for (int i = 0 ; i < 100000; i++){
        withString+="some string";
    }
    System.out.println("strings:" + (System.currentTimeMillis() - t0));

    t0 = System.currentTimeMillis();
    StringBuffer buf = new StringBuffer();
    for (int i = 0 ; i < 100000; i++){
        buf.append("some string");
    }
    System.out.println("Buffers : "+(System.currentTimeMillis() - t0));

    t0 = System.currentTimeMillis();
    StringBuilder building = new StringBuilder();
    for (int i = 0 ; i < 100000; i++){
        building.append("some string");
    }
    System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}

结果:字符串:319740缓冲区:23建设者:7!

因此,构建器比缓冲区更快,比字符串串联更快。现在让我们为多个线程使用Executor:

public class StringsPerf {

    public static void main(String[] args) {

        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
        //With Buffer
        StringBuffer buffer = new StringBuffer();
        for (int i = 0 ; i < 10; i++){
            executorService.execute(new AppendableRunnable(buffer));
        }
        shutdownAndAwaitTermination(executorService);
        System.out.println(" Thread Buffer : "+ AppendableRunnable.time);

        //With Builder
        AppendableRunnable.time = 0;
        executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
        StringBuilder builder = new StringBuilder();
        for (int i = 0 ; i < 10; i++){
            executorService.execute(new AppendableRunnable(builder));
        }
        shutdownAndAwaitTermination(executorService);
        System.out.println(" Thread Builder: "+ AppendableRunnable.time);

    }

   static void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown(); // code reduced from Official Javadoc for Executors
        try {
            if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
                pool.shutdownNow();
                if (!pool.awaitTermination(60, TimeUnit.SECONDS))
                    System.err.println("Pool did not terminate");
            }
        } catch (Exception e) {}
    }
}

class AppendableRunnable<T extends Appendable> implements Runnable {

    static long time = 0;
    T appendable;
    public AppendableRunnable(T appendable){
        this.appendable = appendable;
    }

    @Override
    public void run(){
        long t0 = System.currentTimeMillis();
        for (int j = 0 ; j < 10000 ; j++){
            try {
                appendable.append("some string");
            } catch (IOException e) {}
        }
        time+=(System.currentTimeMillis() - t0);
    }
}

现在StringBuffers需要157毫秒才能完成100000次追加。这不是同一个测试,但与之前的37毫秒相比,您可以放心地假设,使用多线程时,StringBuffers追加的速度较慢。原因是JIT/hotspot/compiler/something在检测到不需要检查锁时会进行优化。

但是对于StringBuilder,您有java.lang.ArrayIndexOutOfBoundsException,因为并发线程试图在不应该添加的地方添加一些内容。

结论是,您不必追逐StringBuffers。如果您有线程,在尝试获得几纳秒之前,请考虑它们正在做什么。

StringBuilder和StringBuffer几乎相同。不同之处在于StringBuffer是同步的,而StringBuilder不是。尽管StringBuilder比StringBuffer更快,但性能差异很小。StringBuilder是SUN对StringBuffer的替代品。它只是避免了所有公共方法的同步。相反,它们的功能是相同的。

良好使用示例:

如果您的文本将要更改并被多个线程使用,那么最好使用StringBuffer。如果您的文本将要更改,但被单个线程使用,请使用StringBuilder。

下面是Stringvs StringBuffer vs StringBuilder的性能测试结果。最后,StringBuilder赢得了测试。测试代码和结果见下文。

代码:

private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test

int loop = 100000;
long start = 0;

// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
  str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");

// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
  sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");

// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
  sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");

  }

在ideone上执行我

结果:

100000次迭代,用于添加单个文本

String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms

10000次迭代,用于添加单个文本

String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms

StringBuilder比StringBuffer更快,因为它不同步。

下面是一个简单的基准测试:

public class Main {
    public static void main(String[] args) {
        int N = 77777777;
        long t;

        {
            StringBuffer sb = new StringBuffer();
            t = System.currentTimeMillis();
            for (int i = N; i --> 0 ;) {
                sb.append("");
            }
            System.out.println(System.currentTimeMillis() - t);
        }

        {
            StringBuilder sb = new StringBuilder();
            t = System.currentTimeMillis();
            for (int i = N; i > 0 ; i--) {
                sb.append("");
            }
            System.out.println(System.currentTimeMillis() - t);
        }
    }
}

测试运行得出StringBuffer为2241ms,StringBuilder为753ms。