StringBuilder 和 StringBuffer 的区别
-
21-08-2019 - |
题
之间的主要区别是什么 StringBuffer
和 StringBuilder
?在决定其中任何一项时是否存在任何性能问题?
解决方案
StringBuffer
是同步的, StringBuilder
不是。
其他提示
StringBuilder
比 StringBuffer
因为它不是 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 测试运行 给出的数字 2241 ms
为了 StringBuffer
与 753 ms
为了 StringBuilder
.
基本上,而StringBuffer
不StringBuilder
方法是同步的。
的操作是“几乎”是相同的,但在一个单独的线程使用同步方法是矫枉过正。
这是相当多了。
这 StringBuilder的API 引用:
此类[StringBuilder的]提供的StringBuffer兼容的API,的但不保证同步的即可。这个类设计用作在其中正在使用由单个线程字符串缓冲区地方简易替换为StringBuffer的(如通常是这种情况)。如果可能,建议这个类中优先使用的StringBuffer作为的这将是下大多数实现更快。强>
因此,它是为了代替它。
同样的事情发生Vector
和ArrayList
。
但需要去用一个例子的帮助下,明显的区别?
的StringBuffer或StringBuilder的
只需使用StringBuilder
,除非你真的要分享的线程之间的缓冲。 StringBuilder
是不同步的(较少的开销=更有效)原始同步StringBuffer
类的弟弟。强> 的
StringBuffer
来到第一。太阳在所有条件下与正确性有关,所以他们把它同步,使其线程安全,以防万一。
StringBuilder
后来。最StringBuffer
的用途是单螺纹和不必要的支付同步的成本。
由于StringBuilder
是一个的 直接替代 强>任何实施例之间,用于不同步StringBuffer
,就不会有差异。
如果您是试图线程之间共享,则可以使用StringBuffer
,但考虑更高级别的同步是否是必要的,例如也许不是使用StringBuffer的,你应该是同步使用StringBuilder的方法。
首先让看到的相似性强>: 双方的StringBuilder和StringBuffer是可变的。这意味着你可以改变它们的内容,与在相同的位置。
<强>差异强>: 的StringBuffer是可变且同步的为好。其中作为StringBuilder的是可变的,但不是默认同步。
同步(同步)的的含义强>: 当一些事情是同步的,那么多个线程可以访问,并与出过任何问题或副作用修改。 StringBuffer的同步,所以可以用任何问题多个线程使用它。
以使用哪一个时吗 StringBuilder的:当你需要一个字符串,它可以修改,且只有一个线程访问和修改它。 StringBuffer的:当需要一个字符串,它可以是可修改的,和多个线程访问和修改它
注意强>:不要用StringBuffer不必要,即,如果只有一个线程是修改和访问它,因为它有大量的锁定和解锁代码用于同步,这将不必要地采取不使用它占用CPU时间。除非需要,不要使用锁。
在单线程中, 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!
因此,构建器比缓冲区更快,并且比字符串连接快得多。现在让我们使用一个 执行者 对于多线程:
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/热点/编译器/某些东西在检测到存在时会进行优化 不 需要检查锁。
但 使用 StringBuilder,您会遇到 java.lang.ArrayIndexOutOfBoundsException, ,因为并发线程试图在不应该添加的地方添加一些内容。
结论是您不必追逐 StringBuffer。在有线程的地方,在尝试获得几纳秒之前,请考虑它们正在做什么。
的StringBuilder在Java 1.5的引入,所以它不会与早期的JVM工作。
从 Javadoc中:
StringBuilder类提供的StringBuffer兼容的API,但不保证同步。这个类设计用作在其中正在使用由单个线程字符串缓冲区地方简易替换为StringBuffer的(如通常是这种情况)。如有可能,建议,这个类优先于StringBuffer的使用,因为它会根据大多数实现更快。
相当好的问题
下面是差异,我已经注意到:
的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.
普通的事情: -
两者具有相同签名的方法相同的方法。两者都是可变的。
的StringBuilder不是线程安全。字符串缓冲的。这里更多的信息 。
编辑:至于性能,热点踢后,StringBuilder的是赢家。然而,对于小的迭代中,性能差异是可以忽略的。
和StringBuilder
是StringBuffer
几乎相同。不同的是,StringBuffer
是同步的,StringBuilder
不是。虽然,StringBuilder
比StringBuffer
更快,性能上的差异是非常小的。 StringBuilder
是SUN的替补StringBuffer
的。它只是避免了所有的公共方法同步。而重要的是,它们的功能是相同的。
好使用示例:
如果您的文本是不会改变,并使用多线程,那么最好是使用StringBuffer
。如果您的文本是不会改变,但使用一个线程,然后使用StringBuilder
。
StringBuffer
- 同步因此线程安全
- 线程安全因此速度慢
StringBuilder
- Java 5.0中引入
- 异步因此快速高效
- 如果用户愿意,则明确需要同步它
- 您可以将其替换为
StringBuffer
没有任何其他改变
字符串缓冲区
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和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
是不可变的。
StringBuffer
是一个可变且同步的。
StringBuilder
也是可变的,但是其不同步。
在的Javadoc 解释的区别是:
此类提供的StringBuffer兼容的API,但不保证同步。这个类设计用作在其中正在使用由单个线程字符串缓冲区地方简易替换为StringBuffer的(如通常是这种情况)。如果可能,建议这个类优先于StringBuffer的使用,因为它会根据大多数实现更快。
StringBuilder
(在 Java 5 中引入)与 StringBuffer
, ,但它的方法不同步。这意味着它比后者具有更好的性能,但缺点是它不是线程安全的。
读 教程 更多细节。
一个简单的程序示出的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");
}
}
}
更好地使用的StringBuilder,因为它是不同步的并且为此较好的性能。 StringBuilder的是一个简易替换旧的StringBuffer。
StringBuffer
是同步的,但StringBuilder
不是。其结果是,StringBuilder
比StringBuffer
更快。
<强>的StringBuffer 强> 是可变的。它可以在长度和内容方面的改变。 StringBuffers是线程安全的,这意味着他们已经同步方法来控制访问,以便只有一个线程可以同时访问一个StringBuffer对象的同步代码。因此,StringBuffer的对象通常是安全的在多线程环境中,其中多个线程可能试图同时访问相同的StringBuffer对象使用。
<强>的StringBuilder 强> StringBuilder类是非常相似的StringBuffer,不同之处在于它的访问不同步的,因此它不是线程安全的。通过不同步,StringBuilder的性能可以比StringBuffer的更好。因此,如果你是在单线程环境中工作,使用的StringBuilder而不是StringBuffer的可能会导致更高的性能。这也是其他情况真如一个StringBuilder局部变量(即,方法内的变量),其中只有一个线程将是访问StringBuilder对象。
字符串缓冲区:
- 多线程
- 同步
- 比 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的对象。
的StringBuffer用于将更改存储的字符串(字符串对象不能被更改)。它根据需要自动扩展。相关的类:字符串,CharSequence的
的StringBuilder在Java 5中加入它是在所有方面的StringBuffer不同之处在于它是不同步的,这意味着,如果多个线程同时访问它,可能有麻烦相同。为单线程程序,最常见的情况下,避免了同步的开销使得StringBuilder的非常稍快。
有StringBuilder的和StringBuffer之间没有根本的不同,它们之间只存在一些区别。在StringBuffer的方法是同步的。这意味着,在同一时间只有一个线程可以对它们进行操作。如果有一个以上的线程,则第二个线程必须等待第一个完成,第三个将不得不等待第一和第二个完成等等。这使得该方法很慢,因此在StringBuffer的情况下的性能是低的。
在另一方面StringBuilder的是非同步的。这意味着,在一个时间多个线程可以在同一时间同一StrinBuilder对象上操作。这使得该方法非常快,因此StringBuilder的性能是高的。
由于StringBuffer
是同步的,它需要一些额外的努力,因此,基于perforamance,比StringBuilder
其有点慢。
的字符串是一个不可变的对象,这意味着该值不能被改变,其中为的StringBuffer是可变的。
在的StringBuffer因此被同步线程安全其中作为StringBuilder的是不是和适合于只是单线程实例。
主要的区别是StringBuffer
是syncronized但StringBuilder
是not.If你需要使用多个线程,然后StringBuffer的是recommended.But,按照执行速度StringBuilder
比StringBuffer
更快,因为它不是syncronized。
检查同步追加方法的内部结构 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;
}
由于追加是 synchronized
, StringBuffer
相比之下有性能开销 StrinbBuilder
在多线程场景下。只要您不在多个线程之间共享缓冲区,就可以使用 StringBuilder
, ,由于没有 synchronized
在附加方法中。
下面是用于<强>字符串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");
}
<强>结果强>:
100000迭代添加单个文本
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000迭代添加单个文本
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
- StringBuffer 是线程安全的,但 StringBuilder 不是线程安全的。
- StringBuilder 比 StringBuffer 更快。
- StringBuffer is synchronized whereas StringBuilder is not synchronized.
每个存在于StringBuffer的方法是同步的。 因此在一个时间只有一个线程被允许工作StringBuffer对象。 它增加了一个线程的等待时间,创建性能问题 克服这个问题的SUN人们在1.5版本intoduced StringBuilder的。