StringBuilder和StringBuffer之间的区别

时间:2008-12-10 04:34:26

标签: java stringbuilder stringbuffer

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

33 个答案:

答案 0 :(得分:1565)

StringBuffer已同步,StringBuilder未同步。

答案 1 :(得分:702)

StringBuilderStringBuffer快,因为它不是synchronized

这是一个简单的基准测试:

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);
        }
    }
}

test run2241 ms提供StringBuffer753 ms StringBuilder的数字。

答案 2 :(得分:235)

基本上,StringBuffer方法是同步的,而StringBuilder则不是。

操作“几乎”相同,但在单个线程中使用同步方法是过度的。

这几乎就是它。

引自StringBuilder API

  

此类[StringBuilder]提供与StringBuffer兼容的API,但不保证同步。此类设计用作StringBuffer的替代品,用于单个线程使用字符串缓冲区的位置(通常情况下)。在可能的情况下,建议使用此类优先于StringBuffer,因为在大多数实现中它会更快。

所以它取代了它。

VectorArrayList也是如此。

答案 3 :(得分:160)

  

但是需要在示例的帮助下获得明显的差异吗?

     

StringBuffer或StringBuilder

只需使用StringBuilder,除非您真的想在线程之间共享缓冲区。 StringBuilder是原始同步StringBuffer类的未同步(开销较小=效率较高)的弟弟。

StringBuffer排在第一位。 Sun在所有条件下都关注正确性,因此他们将其同步化以使其在线程安全以防万一。

StringBuilder后来来了。 StringBuffer的大部分用法都是单线程,并且不必要地支付同步费用。

由于StringBuilder是没有同步的StringBuffer 替换 ,因此任何示例之间都不会有差异。

如果 尝试在线程之间共享,则可以使用StringBuffer,但要考虑是否需要更高级别的同步,例如或许不使用StringBuffer,你应该同步使用StringBuilder的方法。

答案 4 :(得分:76)

首先让我们看一下相似之处: StringBuilder和StringBuffer都是可变的。这意味着您可以在同一位置更改它们的内容。

<强>差异: StringBuffer也是可变的和同步的。 StringBuilder可变,但默认情况下不同步。

同步(同步)的含义: 当某些东西被同步时,多个线程可以访问,并修改它而不会出现任何问题或副作用。 StringBuffer是同步的,因此您可以将它与多个线程一起使用而没有任何问题。

哪一个使用? StringBuilder:当你需要一个可以修改的字符串时,只有一个线程正在访问和修改它。 StringBuffer:当你需要一个可以修改的字符串,并且多个线程正在访问和修改它时。

注意:不要不必要地使用StringBuffer,即如果只有一个线程正在修改和访问它,请不要使用它,因为它有很多锁定和解锁代码用于同步,这将不必要地采取CPU时间。除非需要,否则不要使用锁。

答案 5 :(得分:48)

在单线程中,由于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!

所以构建者比Buffers更快,并且比字符串连接更快。 现在让我们为多个线程使用执行程序

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对于100000个追加采用 157 ms 。它不是相同的测试,但与之前的37 ms相比,您可以放心地假设 StringBuffers追加使用多线程时速度较慢。原因是JIT / hotspot / compiler / something在检测到 no 需要检查锁时进行优化。

但是使用StringBuilder,你有java.lang.ArrayIndexOutOfBoundsException ,因为并发线程试图添加不应该的东西。

结论是您不必追逐StringBuffers。在你有线程的地方,在尝试获得几纳秒之前考虑一下他们在做什么。

答案 6 :(得分:41)

StringBuilder是在Java 1.5中引入的,因此它不适用于早期的JVM。

来自Javadocs

  

StringBuilder类提供与StringBuffer兼容的API,但不保证同步。此类设计用作StringBuffer的替代品,用于单个线程使用字符串缓冲区的位置(通常情况下)。在可能的情况下,建议首先使用此类优先于StringBuffer,因为在大多数实现中它会更快。

答案 7 :(得分:35)

  

非常好的问题

以下是差异,我注意到了:

StringBuffer: -

StringBuffer is  synchronized
StringBuffer is  thread-safe
StringBuffer is  slow (try to write a sample program and execute it, it will take more time than StringBuilder)

的StringBuilder: -

 StringBuilder is not synchronized 
 StringBuilder is not thread-safe
 StringBuilder performance is better than StringBuffer.

常见的事情: -

  

两者都有相同的签名相同的方法。两者都是可变的。

答案 8 :(得分:22)

StringBuilder不是线程安全的。 String Buffer是。更多信息here

编辑:至于性能,在hotspot开始之后,StringBuilder就是胜利者。但是,对于小的迭代,性能差异可以忽略不计。

答案 9 :(得分:21)

StringBuilderStringBuffer几乎相同。区别在于StringBuffer已同步且StringBuilder未同步。虽然StringBuilderStringBuffer快,但性能差异很小。 StringBuilder是SUN替代StringBuffer。它只是避免了所有公共方法的同步。而不是那样,他们的功能是相同的。

良好用法示例:

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

答案 10 :(得分:20)

StringBuffer

  • 同步因此线程安全
  • 线程安全因此很慢

StringBuilder

  • 在Java 5.0中引入
  • 异步因此快速&amp;高效
  • 用户明确需要同步它,如果他想要
  • 您可以将其替换为StringBuffer而无需任何其他更改

答案 11 :(得分:18)

<强>的StringBuffer

StringBuffer是可变的意味着可以更改对象的值。通过StringBuffer创建的对象存储在堆中。 StringBuffer与StringBuilder具有相同的方法,但StringBuffer中的每个方法都是同步的,StringBuffer是线程安全的。

因此,它不允许两个线程同时访问同一个方法。每个方法一次只能由一个线程访问。

但由于线程安全属性,StringBuffer的性能会受到攻击,因此线程安全也有缺点。因此,当调用每个类的相同方法时,StringBuilder比StringBuffer更快。

可以更改StringBuffer值,这意味着可以将其分配给新值。如今它是一个最常见的面试问题,上述课程之间的差异。 可以使用String将String Buffer转换为字符串 toString()方法。

StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .

demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer

<强>的StringBuilder

StringBuilder与StringBuffer相同,即它将对象存储在堆中,也可以对其进行修改。 StringBuffer和StringBuilder之间的主要区别在于StringBuilder也不是线程安全的。 StringBuilder很快,因为它不是线程安全的。

StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified

demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder

enter image description here

资源:String Vs StringBuffer Vs StringBuilder

答案 12 :(得分:16)

String是不可变的。

StringBuffer是一个可变且同步的。

StringBuilder也是可变的,但不同步。

答案 13 :(得分:11)

javadoc解释了差异:

  

此类提供与StringBuffer兼容的API,但不保证同步。此类设计用作StringBuffer的替代品,用于单个线程使用字符串缓冲区的位置(通常情况下)。在可能的情况下,建议首先使用此类优先于StringBuffer,因为在大多数实现中它会更快。

答案 14 :(得分:10)

StringBuilder(在Java 5中引入)与StringBuffer相同,但其方法不同步。这意味着它具有比后者更好的性能,但缺点是它不是线程安全的。

阅读tutorial了解详情。

答案 15 :(得分:6)

一个简单的程序,说明了StringBuffer和StringBuilder之间的区别:

/**
 * Run this program a couple of times. We see that the StringBuilder does not
 * give us reliable results because its methods are not thread-safe as compared
 * to StringBuffer.
 * 
 * For example, the single append in StringBuffer is thread-safe, i.e.
 * only one thread can call append() at any time and would finish writing
 * back to memory one at a time. In contrast, the append() in the StringBuilder 
 * class can be called concurrently by many threads, so the final size of the 
 * StringBuilder is sometimes less than expected.
 * 
 */
public class StringBufferVSStringBuilder {

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

        int n = 10; 

        //*************************String Builder Test*******************************//
        StringBuilder sb = new StringBuilder();
        StringBuilderTest[] builderThreads = new StringBuilderTest[n];
        for (int i = 0; i < n; i++) {
            builderThreads[i] = new StringBuilderTest(sb);
        }
        for (int i = 0; i < n; i++) {
            builderThreads[i].start();
        }
        for (int i = 0; i < n; i++) {
            builderThreads[i].join();
        }
        System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());

        //*************************String Buffer Test*******************************//

        StringBuffer sb2 = new StringBuffer();
        StringBufferTest[] bufferThreads = new StringBufferTest[n];
        for (int i = 0; i < n; i++) {
            bufferThreads[i] = new StringBufferTest(sb2);
        }
        for (int i = 0; i < n; i++) {
            bufferThreads[i].start();
        }
        for (int i = 0; i < n; i++) {
            bufferThreads[i].join();
        }
        System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());

    }

}

// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {

    StringBuilder sb;

    public StringBuilderTest (StringBuilder sb) {
        this.sb = sb;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            sb.append("A");
        }

    }
}


//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {

    StringBuffer sb2;

    public StringBufferTest (StringBuffer sb2) {
        this.sb2 = sb2;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            sb2.append("A");
        }

    }
}

答案 16 :(得分:4)

更好地使用StringBuilder,因为它不是同步的,因此性能更好。 StringBuilder是旧StringBuffer的替代品。

答案 17 :(得分:4)

<强>的StringBuffer:

  • 多线程
  • 同步
  • 比StringBuilder慢

<强>的StringBuilder

  • 单线程
  • 不同步化
  • 比以往更快的字符串

答案 18 :(得分:4)

String-Builder

int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.

<强>字符串缓冲区

StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);  

建议尽可能使用StringBuilder,因为它比StringBuffer更快。但是,如果线程安全是必要的,最好的选择是StringBuffer对象。

答案 19 :(得分:4)

StringBuffer已同步,但StringBuilder未同步。因此,StringBuilderStringBuffer快。

答案 20 :(得分:4)

<强>的StringBuffer 是可变的。它可以在长度和内容方面发生变化。 StringBuffers是线程安全的,这意味着它们具有控制访问的同步方法,因此一次只有一个线程可以访问StringBuffer对象的同步代码。因此,StringBuffer对象通常可以在多线程环境中使用,其中多线程可能同时尝试访问同一个StringBuffer对象。

<强>的StringBuilder StringBuilder类与StringBuffer非常相似,只是它的访问不同步,因此它不是线程安全的。通过不同步,StringBuilder的性能可以比StringBuffer更好。因此,如果您在单线程环境中工作,则使用StringBuilder而不是StringBuffer可能会提高性能。对于其他情况也是如此,例如StringBuilder局部变量(即方法中的变量),其中只有一个线程将访问StringBuilder对象。

答案 21 :(得分:3)

StringBuffer和StringBuilder Source:之间的区别

enter image description here

答案 22 :(得分:3)

StringBuilder和StringBuffer之间没有基本的区别,它们之间只存在一些差异。在StringBuffer中,方法是同步的。这意味着一次只有一个线程可以对它们进行操作。如果有多个线程,则第二个线程必须等待第一个线程完成,第三个线程必须等待第一个和第二个线程完成,依此类推。这使得该过程非常缓慢,因此在StringBuffer的情况下性能很低。

另一方面,StringBuilder是非同步的。这意味着多个线程可以同时在同一个StrinBuilder对象上运行。这使得该过程非常快,因此StringBuilder的性能很高。

答案 23 :(得分:3)

由于StringBuffer已同步,因此需要额外的努力,因此基于性能,它比StringBuilder慢一点。

答案 24 :(得分:3)

StringBuffer用于存储将被更改的字符串(不能更改String对象)。它会根据需要自动扩展。相关类:String,CharSequence。

StringBuilder是在Java 5中添加的。它在所有方面都与StringBuffer相同,只是它没有同步,这意味着如果多个线程同时访问它,可能会有麻烦。对于单线程程序,最常见的情况是,避免同步开销,使StringBuilder的速度稍快一些。

答案 25 :(得分:2)

主要区别是StringBuffer是同步的,但StringBuilder不是。如果你需要使用多个线程,那么建议使用StringBuffer。但是,根据执行速度StringBuilderStringBuffer更快,因为它不同步。

答案 26 :(得分:2)

检查StringBuffer的同步追加方法的内部和StringBuilder的非同步追加方法。

StringBuffer

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

public synchronized StringBuffer append(Object obj) {
    super.append(String.valueOf(obj));
    return this;
}

public synchronized StringBuffer append(String str) {
    super.append(str);
    return this;
}

StringBuilder

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
}

public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

由于追加是synchronized,因此StringBuffer与多线程场景中的StrinbBuilder相比具有性能开销。只要您不在多个线程之间共享缓冲区,请使用StringBuilder,由于附加方法中缺少synchronized,因此速度很快。

答案 27 :(得分:2)

String是一个不可变对象,这意味着无法更改StringBuffer可变的值。

StringBuffer是同步的,因此线程安全,而StringBuilder不是,只适用于单线程实例。

答案 28 :(得分:1)

这是 String vs 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");

  }

Execute Me on 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

答案 29 :(得分:1)

  • StringBuffer是线程安全的,但StringBuilder不是线程安全的。
  • StringBuilder比StringBuffer快。
  • StringBuffer已同步,而StringBuilder未同步 同步。

答案 30 :(得分:0)

StringBuffer中存在的每个方法都是同步的。 因此,一次只允许一个线程操作StringBuffer对象。 它增加了线程的等待时间并创建了性能问题 为了解决这个问题,SUN People在1.5版本中引入了StringBuilder。

答案 31 :(得分:0)

StringBuffer已同步且线程安全,StringBuilder未同步且速度更快。

答案 32 :(得分:0)

其他人正确地指出了两者之间的主要区别。但是,在性能方面,我想补充一点,JVM级别的优化“ Lock Elision”可以使同步上下文中的性能差异几乎不存在。 herehere

是这方面的绝佳读物