java - 什么时候使用stringbuilder - 什么时候用stringbuilder




StringBuilder和StringBuffer的区别 (20)

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


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

StringBuffer或StringBuilder

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

StringBuffer排在第一位。 Sun在所有情况下都关心正确性,所以为了防万一,他们让它同步以保证线程安全。

StringBuilder来了。 StringBuffer大部分用途都是单线程的,并且不必要地支付同步的成本。

由于StringBuilder是没有同步的StringBuffer 替换 ,所以任何示例之间都不会有区别。

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


很好的问题

以下是我注意到的差异:

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不是线程安全的。 字符串缓冲区是。 更多信息here

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


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

StringBuilder

StringBuilder类提供了与StringBuffer兼容的API,但不保证同步。 此类用于在单个线程正在使用字符串缓冲区的位置(如通常情况下)用作StringBuffer的嵌入式替换。 在可能的情况下,建议将此类优先用于StringBuffer,因为在大多数实现中它会更快。



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

测试运行给出了StringBuffer2241 ms数与StringBuffer 753 ms数。


String是不可变的。

StringBuffer是一个可变和同步的。

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


StringBuffer

  • 因此同步线程安全
  • 线程安全因此缓慢
  • -

StringBuilder

  • 在Java 5.0中引入
  • 异步因此快速和高效
  • 用户明确需要同步它,如果他想
  • 您可以将其替换为StringBuilder而不做任何其他更改

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

阅读tutorial了解更多详情。


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

良好用法的例子:

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


StringBuffer的:

  • 多线程
  • 同步
  • 比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

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

资源: 字符串Vs StringBuffer Vs StringBuilder


一个说明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和StringBuffer之间没有基本的区别,只是它们之间存在一些差异。 在StringBuffer中,这些方法是同步的。 这意味着一次只有一个线程可以对它们进行操作。 如果有多个线程,那么第二个线程将不得不等待第一个线程完成,第三个线程将不得不等待第一个线程完成,以此类推。 这使得该过程非常缓慢,因此在StringBuffer情况下的性能很低。

另一方面,StringBuilder是不同步的。 这意味着一次有多个线程可以同时在同一个StrinBuilder对象上运行。 这使得该过程非常快速,因此StringBuilder的性能很高。


在单线程中,由于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 ms相比,您可以放心地认为, 使用多线程时StringBuffers追加速度会更慢 。 原因是JIT /热点/编译器/某些东西在检测到不需要检查锁时会进行优化。

但是对于StringBuilder,你有java.lang.ArrayIndexOutOfBoundsException ,因为一个并发线程试图添加它不应该添加的东西。

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


字符串是一个不可变的对象,这意味着在StringBuffer可变的情况下,值不能被改变。

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


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


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






stringbuffer