StringBuilder和StringBuffer的区别

StringBufferStringBuilder的主要区别是什么?在选择其中任何一个时是否有任何性能问题?

870566 次浏览

#0是同步的,#1不是。

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

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

差不多就是这样了。

引用应用程序接口

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

所以它被用来代替它。

VectorArrayList也是如此。

StringBuilder是在Java1.5中引入的,因此它不适用于早期的JVM。

javadocs

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

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

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

StringBuffer

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

StringBuilder

  • Java5.0
  • 异步因此快速高效
  • 用户明确需要同步它,如果他想要
  • 您可以将其替换为StringBuffer而无需任何其他更改

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

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

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

#0#1快,因为它不是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);}}}

A试运行给出了StringBuffer2241 msStringBuilder753 ms的数字。

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

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

StringBuilderStringBuffer几乎相同。不同的是StringBuffer是同步的,StringBuilder不是。虽然,StringBuilderStringBuffer快,但性能差异很小。StringBuilder是SUN代替StringBuffer。它只是避免了所有公共方法的同步。相反,它们的功能是相同的。

良好用法示例:

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

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

javadoc解释了差异:

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

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

阅读教程了解更多详情。

但是需要通过一个例子来获得明显的区别吗?

StringBuffer或StringBuilder

简单地使用StringBuilder,除非你真的想在线程之间共享一个缓冲区。StringBuilder是原始同步StringBuffer类的未同步(开销更少=效率更高)的弟弟。

StringBuffer是第一个。Sun关心所有条件下的正确性,所以他们使其同步以使其线程安全以防万一。

StringBuilder出现得更晚。StringBuffer的大多数用途都是单线程,并且不必要地支付了同步的成本。

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

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

在单线程中,StringBuffer并不比StringBuilder慢,这要归功于JVM优化。在多线程中,您不能安全地使用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!

因此Builders比Buffers快,并且比字符串连接快得多。现在让我们对多个线程使用遗嘱执行人

public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);//With BufferStringBuffer 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 BuilderAppendableRunnable.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 Executorstry {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;}
@Overridepublic 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/编译器/某物在检测到有需要检查锁时进行了优化。

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

结论是,你不必追逐StringBuffers。在你有线程的地方,在试图获得几纳秒之前,想想它们在做什么。

String是不可变的。

StringBuffer是可变的和同步的。

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

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

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

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

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

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

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

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

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

一个简单的程序说明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;}
@Overridepublic 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;}
@Overridepublic void run() {for (int i = 0; i < 100; i++) {sb2.append("A");}
}}

非常好的问题

以下是我注意到的差异:

StringBuffer:-

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

StringBuilder:-

 StringBuilder is not synchronizedStringBuilder is not thread-safeStringBuilder performance is better than StringBuffer.

常见的事情:-

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

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

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

StringBuffer:

  • 多线程
  • 同步
  • 比StringBuilder慢

StringBuilder

  • 单线程
  • 未同步
  • 比以往更快String

StringBuilderStringBuffer之间没有基本的区别,它们之间只有一些区别。在StringBuffer中,方法是同步的。这意味着一次只能有一个线程对它们进行操作。如果有多个线程,那么第二个线程将不得不等待第一个线程完成,第三个线程将不得不等待第一个和第二个线程完成,依此类推。这使得过程非常慢,因此StringBuffer的性能很低。

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

检查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是synchronized,因此在多线程场景中,与StrinbBuilder相比,StringBuffer有性能开销。只要你不在多个线程之间共享缓冲区,请使用StringBuilder,由于append方法中没有synchronized,它会很快。

StringBuffer

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

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

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

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

在此处输入图片描述

资源:String vs StringBuffer vs StringBuilder

字符串生成器

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

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

代码

private static void performanceTestStringVsStringbuffereVsStringBuilder() {// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;long start = 0;
// StringString str = null;start = System.currentTimeMillis();for (int i = 1; i <= loop; i++) {str += i + "test";}System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String bufferStringBuffer 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 builderstart = 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 msString Buffer - 5 msString Builder - 4 ms

10000次添加单个文本的迭代

String - 389 msString Buffer - 1 msString Builder - 1 ms
  • StringBuffer是线程安全的,但StringBuilder不是线程安全的。
  • StringBuilder比StringBuffer快。
  • StringBuffer是同步的,而StringBuilder不是已同步。

其他人正确地指出了两者之间的关键差异。然而,就性能而言,我想补充一点,JVM级别的优化“锁定省略”可能会使同步上下文中的性能差异几乎不存在。关于这一点的一个很好的阅读是这里这里

StringBuffer和StringBuilder来源:的区别

在此处输入图片描述

StringBuilder比StringBuffer快,因为StringBuffer是同步的,StringBuffer有自己的char[]缓冲区用于缓存,就像BufferedInputStream一样。

StringBuffer速度较慢的另一个原因是,因为每次追加或删除时,它都会更新变量缓冲区。我测试了它,不知何故,如果我删除超过一万次,StringBuffer的删除方法会更快。