StringBuilder和StringBuffer之间的区别


Answers:


1665

StringBuffer是同步的,StringBuilder不是。


239
和StringBuilder旨在替代不需要同步的StringBuffer
Joel 2009年

95
几乎不需要同步。如果有人想在StringBuilder上进行同步,则只需在实例上用同步的(sb){}包围整个代码块
locka

23
@locka我认为StringBuffer的是不是一个好主意(除非你有需要它的API)vanillajava.blogspot.de/2013/04/...
彼得Lawrey

8
我看到的唯一一个StringBuffer是控制台之类的输出和各种日志实用程序:许多线程可能会冲突输出。由于您不希望混淆2个输出...但是通常在StringBuffer级别进行的同步太低了,因此您将希望在诸如levelm的附加器上进行同步,因此locka的答案是最好的,应该弃用StringBuffer。这样可以节省新手的代码审查时间。
雷米·莫林

20
对于那些将这两者混合使用的人来说,好记号是-BuFFer首先是较旧的版本,因此是同步执行的。较新的Builder类使用Builder模式,并且是异步的。
Datageek

728

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 msStringBufferVS 753 msStringBuilder


10
我将字符串文字更改为更大的名称:“ the quick brown fox”,并获得了更有趣的结果。基本上,它们的速度差不多。我实际上用光了内存,因此我不得不删除七个数字。说明:同步已通过热点进行了优化。基本上,您只是在测量完成此操作所需的时间(可能还会进行更多优化)。
耶尔·范·古普(Jilles van Gurp)2012年

7
您需要先热身。此测试对StringBuffer不公平。另外,如果它确实附加了一些内容,那将是很好的。实际上,我翻转了测试,并添加了一个随机字符串,得到了相反的测试。可以说,人们不能相信简单的基准。相反显示StringBuffer更快。适用于StringBuilder的5164和适用于StringBuffer的3699,hastebin.com/piwicifami.avrasm
mmm

75
这是我第一次看到--> 0循环。花了我一点时间来了解它的含义。这是实际上在实践中使用的东西,而不是通常的...; i > 0; i--语法吗?
RaimundKrämer'15

19
i -->语法角度看,这确实很烦人。由于有关ASCII艺术的评论,我起初以为是一个箭头。
Sameer Puri

14
其他人得出不同的结论:alblue.bandlem.com/2016/04/jmh-stringbuffer-stringbuilder.html。基准测试应该真正由JMH完成,而不是简单main()的基准测试。此外,您的基准测试也不公平。没有热身。
卢卡斯·埃德

249

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

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

差不多了。

引用StringBuilder API

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

因此它被替代了。

同样的事情发生VectorArrayList


1
还有HashtableHashMap
shmosel

176

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

StringBuffer或StringBuilder

StringBuilder除非您确实试图在线程之间共享缓冲区,否则请简单使用。StringBuilder是原始同步StringBuffer类的未同步(开销较小=更有效)的弟弟。

StringBuffer首先。Sun在所有情况下都关注正确性,因此他们将其同步以使其具有线程安全性,以防万一。

StringBuilder以后再来 大多数的使用StringBuffer都是单线程的,不必要地支付了同步的费用。

由于StringBuilder直接替代StringBuffer不同步时,就不会有任何的例子之间的差异。

如果您线程之间试图分享,你可以使用StringBuffer,但考虑更高级别的同步是否是必要的,例如,也许不是使用StringBuffer的问题,您应该同步的是使用StringBuilder方法。


14
第一个好的答案!!关键是“除非您在线程之间共享缓冲区”
AlexWien

1
很详细的答案!

81

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

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

同步(synchronization)的含义:当某事物同步时,多个线程可以访问并对其进行修改,而不会出现任何问题或副作用。StringBuffer是同步的,因此您可以将其与多个线程一起使用而不会出现任何问题。

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

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


2
只想提及StringBuffer的INDIVIDUAL方法调用是线程安全的。但是,如果您有多行代码,请使用同步代码块来保证线程安全,并带有一些锁/监控器(按照常规方法...)。基本上,不要仅仅假设立即使用线程安全库就可以保证您程序中的线程安全!
Kevin Lee

57

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

因此,Builder比Buffers快,而WAY比字符串连接快。现在,我们将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 ms相比,您可以放心地假设StringBuffers追加在使用multithreading时较慢。其原因是,在JIT /热点/编译器/东西使得优化,当它检测到有没有必要检查锁。

但是,使用StringBuilder可以使用java.lang.ArrayIndexOutOfBoundsException,因为并发线程会尝试在不应添加的位置添加内容。

结论是您不必追求StringBuffers。在有线程的地方,请先考虑一下它们在做什么,然后再尝试增加几纳秒的时间。


5
您忘记了做“ t0 = System.currentTimeMillis();” 在进行StringBuilder测试之前。因此,为StringBuilder显示的图实际上是运行stringbuffer和stringbuilder测试所花费的时间。添加这一行,您将看到StringBuilder的运行速度快了两倍。
Gena Batsyan

请注意,这withString+="some string"+i+" ; ";并不等效于其他两个循环,因此不是公平的比较。
戴夫·贾维斯

正确,更正。思想字符串仍然很慢。
Nicolas Zozol 2015年

您能解释一下为什么StringBuilder引发ArrayIndexOutOfBoundsException的原因吗
Alireza Fattahi 2015年

您应该将JMH用作基准。您的基准确实不准确。
卢卡斯·埃德

42

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

Javadocs

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


13
1.4的使用寿命已经结束,因此似乎不太值得担心1.5之前的版本。
Tom Hawtin-大头钉

@ tomHawtin-tackline不一定-我们大多数人每天都在使用1.4版之前的企业产品。BlackBerry Java也基于1.4,并且仍然是最新的。
理查德·勒·马修里尔

CDC和CLDC没有StringBuilder
Jin Kwon

37

很好的问题

我注意到这是差异:

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.

普通事:-

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


23

StringBuffer

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

StringBuilder

  • 在Java 5.0中引入
  • 异步,因此快速高效
  • 用户明确需要进行同步(如果需要)
  • 您可以将其替换为StringBuffer没有任何其他更改

注意:只有单个操作是线程安全的,而多个操作则不是。例如,如果你调用append两次,或appendtoString没有不安全的。
彼得·劳瑞

22

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

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


21

StringBuilderStringBuffer几乎一样。区别在于StringBuffer已同步,StringBuilder而并非同步。尽管StringBuilder比快StringBuffer,但性能差异很小。StringBuilder是SUN的替代品StringBuffer。它只是避免了所有公共方法的同步。与其相反,它们的功能是相同的。

良好用法示例:

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


19

字符串缓冲区

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

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

但是,由于线程安全属性会导致StringBuffer的性能下降,因此线程安全也是不利的。因此,在调用每个类的相同方法时,StringBuilder比StringBuffer快。

可以更改StringBuffer的值,这意味着可以将其分配给新值。如今,这是一个最常见的面试问题,即上述课程之间的差异。可以使用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

在此处输入图片说明

资源:字符串与字符串缓冲与字符串构建器


StringBuilder是不可变的并且String类型是可变的
Brinda Rathod '18

我不同意Strings和StringBuilders是“快速”的,而StringBuffers是“非常慢的”。请参阅以上答案。
FireCubez

17

String 是一成不变的。

StringBuffer 是可变且同步的。

StringBuilder 也可变,但不同步。


另外,StringBuffer锁定线程以访问该线程安全数据,这就是操作缓慢的原因。StringBuilder不会锁定线程,而是以多线程方式运行,因此速度很快。字符串-当您不需要连接字符串时,这是个好方法,但是当您需要它时,可以使用StringBuilder->因为字符串每次都会在堆中创建新对象,但是StringBuilder返回相同的对象……
Musa

11

javadoc的解释的区别:

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


10

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

阅读教程以获取更多详细信息。


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

    }
}

4

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

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


4
单线程程序在Java中不是最常见的情况,但是StringBuilder‍通常是方法本地的,在方法中它们仅对一个线程可见。
finnw 2011年


4

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

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


4

StringBuffer:

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

StringBuilder

  • 单线程
  • 不同步
  • 比以往任何时候都更快

2
更确切地说,String c = a + b等于String c = new StringBuilder().append(a).append(b).toString(),所以它不会更快。您创建的每串分配一个新的,而你可能只有一个这是唯一的(String d = a + b; d = d + c;String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();同时StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();将节省一个StringBuilder的instanciation)。
2015年

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


如果需要线程安全,最好的选择是使用StringBuilder,因为StringBuffer仅对单个操作是线程安全的。对于多种操作,您需要显式锁定。
彼得·劳瑞

4

更好地使用,StringBuilder因为它不同步,因此提供了更好的性能。StringBuilder是较早版本的直接替代StringBuffer


3
@Mark为true,但大多数情况下StringBu(ff|ild)er是仅由单个线程使用的局部变量。
gabuzo 2011年

1
@MarkMcKenna:即使在多线程应用程序中,通常也不得不使用外部锁定,或者做一些额外的工作来避免这种情况。例如,如果两个线程各自希望将包含多个字符串的记录追加到stringbuilder中,则它们将不得不汇总要添加的数据,然后将其作为一个单元添加,即使这样会更快(没有线程问题)简单地执行一系列离散的追加操作。
超级猫2014年


3

StringBuilder和之间没有基本区别,它们之间StringBuffer仅存在一些区别。在StringBuffer方法上是同步的。这意味着一次只能有一个线程对其进行操作。如果有多个线程,则第二个线程将必须等待第一个线程完成,而第三个线程将必须等待第一个和第二个线程完成,依此类推。这使处理过程非常缓慢,因此在StringBuffer很低。

另一方面,StringBuilder是不同步的。这意味着一次多个线程可以同时StringBuilder在同一对象上操作。这使处理过程非常快,因此StringBuilder具有很高的性能。


3

A String是一个不变的对象,这意味着该StringBuffer是可变的而不能更改

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


3
仅仅因为StringBuffer具有同步代码,并不一定意味着StringBuffer是线程安全的。考虑以下示例:StringBuffer testingBuffer =“ stackoverflow”; 现在,线程1试图将“ 1”追加到testingBuffer,线程2试图将“ 2”追加到testingBuffer。现在,即使append()方法已同步,您也无法确定testingBuffer的值是“ stackoverflow12”还是“ stackoverflow21”。实际上,Oracle建议Oracle在stringbuffer上使用stringbuilder。希望对您有所帮助:)
Biman Tripathy 2012年

2

主要的区别是StringBuffer同步化的,但是不是同步化StringBuilder的。如果需要使用多个线程,则建议使用StringBuffer。但是,由于执行速度StringBuilderStringBuffer它快,因为它没有同步化。


4
如果仅对StringBuffer执行一次操作,则StringBuffer是线程安全的。我不建议在多线程中使用它,因为很难正确处理。
彼得·劳瑞

@PeterLawrey是什么意思?:-)
Tamad Lang

1
@ b16db0我的意思是,大多数StringBuffer的使用都不是线程安全的,因为它们在没有外部同步的情况下对其进行多次调用,使类变得毫无意义。
彼得·劳里

@PeterLawrey啊,就像StringBuffer仍然需要一个同步的环境。
塔玛德·朗

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

由于append是synchronizedStringBuffer因此与StrinbBuilder多线程方案相比具有性能开销。只要您不在多个线程之间共享缓冲区,请使用StringBuilder,由于没有synchronizedin append方法,因此使用起来很快。


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

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

1

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


该问题的所有其他答案都给出了这种差异。你能强调一些新东西吗?
Nico Haase
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.