1681

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

4

32 回答 32

1747

StringBuffer是同步的,StringBuilder不是。

于 2008-12-10T04:36:23.110 回答
750

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

测试运行给出了2241 msforStringBuffer753 msfor的数量StringBuilder

于 2010-05-05T09:15:08.860 回答
257

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

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

差不多就是这样。

来自StringBuilder API的引用:

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

于是就用它来代替它。

Vector和 也是如此ArrayList

于 2008-12-10T04:37:05.527 回答
187

但是需要借助示例来获得明显的区别吗?

StringBuffer 或 StringBuilder

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

StringBuffer先来。Sun 关心所有条件下的正确性,因此他们将其同步以使其成为线程安全的,以防万一。

StringBuilder后来来了。大多数使用StringBuffer都是单线程的,并且不必要地支付了同步的成本。

由于StringBuilder是不同步的直接替代品StringBuffer因此任何示例之间都不会存在差异。

如果您尝试在线程之间共享,您可以使用StringBuffer,但请考虑是否需要更高级别的同步,例如,如果您同步使用 StringBuilder 的方法,可能而不是使用 StringBuffer。

于 2011-01-25T12:30:54.637 回答
84

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

区别:StringBuffer 也是可变的和同步的。其中 StringBuilder 是可变的,但默认情况下不同步。

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

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

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

于 2013-12-11T07:11:07.613 回答
58

由于 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。在你有线程的地方,想想它们在做什么,然后再尝试获得几纳秒。

于 2012-11-15T16:20:46.073 回答
42

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

Javadocs

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

于 2008-12-10T04:38:27.240 回答
37

很好的问题

这是我注意到的差异:

字符串缓冲区:-

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 is not synchronized 
 StringBuilder is not thread-safe
 StringBuilder performance is better than StringBuffer.

共同点:-

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

于 2014-04-11T20:25:07.433 回答
26

StringBuffer

  • 同步,因此是线程安全的
  • 线程安全,因此速度慢

StringBuilder

  • 在 Java 5.0 中引入
  • 异步因此快速高效
  • 如果需要,用户明确需要同步它
  • 您可以将其替换为StringBuffer无需任何其他更改
于 2008-12-10T05:00:56.773 回答
24

字符串缓冲区

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

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

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

StringBuffer 的值可以改变,这意味着它可以被赋予新的值。现在它是一个最常见的面试问题,上述课程之间的差异。可以使用 toString() 方法将 String Buffer 转换为字符串。

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 和 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

在此处输入图像描述

资源:String Vs StringBuffer Vs StringBuilder

于 2016-09-20T17:40:58.290 回答
23

StringBuilder 不是线程安全的。字符串缓冲区是。更多信息在这里

编辑:至于性能,热点启动后,StringBuilder 是赢家。但是,对于小迭代,性能差异可以忽略不计。

于 2008-12-10T04:41:07.547 回答
21

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

良好用法示例:

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

于 2010-12-03T06:38:49.870 回答
18

String是不可变的。

StringBuffer是可变的和同步的。

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

于 2013-03-18T08:12:55.977 回答
11

javadoc解释了差异:

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

于 2011-01-25T12:21:51.247 回答
11

StringBuffer 和 StringBuilder源码的区别:

在此处输入图像描述

于 2020-07-03T06:41:27.127 回答
10

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

阅读教程了解更多详情。

于 2011-01-25T12:23:47.527 回答
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");
        }

    }
}
于 2014-03-14T18:40:42.357 回答
4

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

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

于 2009-04-23T13:44:45.263 回答
4

StringBuffer是同步的,但StringBuilder不是。结果,StringBuilder比 快StringBuffer

于 2009-12-23T08:42:53.077 回答
4

AString是一个不可变对象,这意味着值不能更改,而StringBuffer它是可变的。

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

于 2010-11-17T11:33:16.023 回答
4

更好地使用StringBuilder,因为它不同步并因此提供更好的性能。StringBuilderStringBuffer.

于 2011-01-25T12:21:09.947 回答
4

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

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

于 2014-09-05T10:02:43.060 回答
4

字符串缓冲区:

  • 多线程
  • 同步的
  • 比 StringBuilder 慢

字符串生成器

  • 单线程
  • 不同步
  • 比以往更快字符串
于 2015-09-27T20:34:41.247 回答
4

字符串生成器

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 对象。

于 2017-02-01T08:44:23.943 回答
3

由于StringBuffer是同步的,它需要一些额外的努力,因此基于性能,它比StringBuilder.

于 2013-07-25T06:39:34.790 回答
3

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

另一方面,StringBuilder不同步。这意味着一次多个线程可以同时对同一个StringBuilder对象进行操作。这使得该过程非常快,因此性能StringBuilder很高。

于 2016-05-10T07:57:53.503 回答
2

主要区别是StringBuffer同步而不是同步。StringBuilder如果你需要使用多个线程,那么建议使用StringBuffer。但是,执行速度StringBuilder比 快StringBuffer,因为它没有同步。

于 2013-11-15T18:05:28.110 回答
2

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

字符串缓冲区

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

字符串生成器

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

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

于 2016-06-09T07:16:23.410 回答
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");

  }

在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
于 2018-08-24T07:59:59.117 回答
1
  • StringBuffer 是线程安全的,但 StringBuilder 不是线程安全的。
  • StringBuilder 比 StringBuffer 快。
  • StringBuffer 是同步的,而 StringBuilder 是不同步的。
于 2018-11-01T17:41:05.103 回答
0

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

于 2013-07-01T13:52:16.967 回答
0

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

于 2019-10-19T09:01:23.750 回答