关于Java:StringBuilder与StringBuffer的差异

Difference between StringBuilder and StringBuffer

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


StringBuffer是同步的,StringBuilder不是同步的。


StringBuilderStringBuffer快,因为它不是synchronized

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
        }
    }
}

测试运行给出了StringBuffer2241 msStringBuilder753 ms的数量。


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

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

差不多就是这样。

从StringBuilder API引用:

This class [StringBuilder] provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.

所以它被用来替代它。

同样的情况也发生在VectorArrayList上。


But needed to get the clear difference with the help of an example?

StringBuffer or StringBuilder

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

以东十一〔二〕先来。Sun关心所有条件下的正确性,所以他们使其同步以使其线程安全,以防万一。

埃多克斯1〔0〕后来来了。StringBuffer的大多数用途是单线程的,不必要地支付同步的成本。

由于在没有同步的情况下,StringBuilderStringBuffer的替代品,因此任何例子之间都不会有差异。

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


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

差异:StringBuffer也是可变和同步的。其中as-stringbuilder是可变的,但默认情况下不同步。

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

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

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


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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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!

所以构建器比缓冲区更快,比字符串连接更快。现在让我们为多个线程使用一个执行器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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是在Java 1.5中引入的,因此它不能用于较早的JVM。

来自javadocs:

StringBuilder class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.


Pretty Good Question

以下是我注意到的区别:

StringBuffer:

1
2
3
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:

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

共同的事情:

Both have same methods with same signatures. Both are mutable.


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

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


StringBuilderStringBuffer几乎相同。区别在于StringBuffer是同步的,StringBuilder不是同步的。虽然StringBuilderStringBuffer快,但性能差别不大。StringBuilder是太阳的替代品。它只是避免了所有公共方法的同步。而不是那样,它们的功能是相同的。

良好使用示例:

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


StringBuffer

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

StringBuilder

  • 在Java 5中介绍
  • 异步,因此快速高效
  • 用户明确需要同步它,如果他想
  • 你可以不做任何其他更改而更换它。


伸缩缓冲器

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

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

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

可以更改StringBuffer值,这意味着可以将其分配给新值。现在最常见的面试问题,就是上述各班之间的差异。字符串缓冲区可以通过使用toString()方法。

1
2
3
4
5
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速度很快,因为它不是线程安全的。

1
2
3
4
5
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

资源:字符串vs字符串缓冲区vs字符串生成器


String是不变的。

StringBuffer是一个可变的和同步的。

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


JavaDoc解释了不同之处:

This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.


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

阅读教程了解更多详细信息。


说明StringBuffer和StringBuilder之间区别的简单程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
 * 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");
        }

    }
}

StringBuffer:

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

字符串拼接

  • 单线螺纹
  • 不同步
  • 比以往任何时候都快的字符串


字符串生成器:

1
2
3
4
5
6
7
int one = 1;
String color ="red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('
'
);
System.out.print(sb);
// Prints"One=1, Colour=red" followed by an ASCII newline.

字符串缓冲区

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

它推荐使用StringBuilder每当可能的,因为它比冰StringBuffer的阿姨。然而,如果必要的线程安全的最好的冰淇淋,冰淇淋StringBuffer对象的选项。


StringBuffer是同步的,但StringBuilder不是同步的。因此,StringBuilderStringBuffer快。


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

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


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


由于StringBuffer是同步的,所以需要做一些额外的工作,因此基于性能,它比StringBuilder慢一些。


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

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


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

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


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

StringBuffer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
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是synchronized,因此与多线程方案中的StrinbBuilder相比,StringBuffer具有性能开销。只要不在多个线程之间共享缓冲区,就使用StringBuilder,这是因为在append方法中没有synchronized,所以速度很快。


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


字符串是不可变的对象,这意味着不能更改值,因为StringBuffer是可变的。

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


  • 冰StringBuffer线程安全的StringBuilder冰槽是线程安全的。
  • 冰比StringBuffer StringBuilder的阿姨。
  • 同步尽头StringBuilder StringBuffer冰冰槽 同步。

这里是性能测试结果为VS VS StringBuilder StringBuffer的字符串。终于,StringBuilder韩元测试。看下面的代码和测试结果。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 execute

结果:

100000迭代增一个单一的文本

1
2
3
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms

增10000迭代的一个单一的文本

1
2
3
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms

StringBuffer中的每个方法都是同步的。因此,一次只允许一个线程操作StringBuffer对象。它增加了线程的等待时间并导致性能问题为了解决这个问题,Sun公司推出了1.5版本的StringBuilder。