Difference between StringBuilder and StringBuffer

后端 未结 30 2382
独厮守ぢ
独厮守ぢ 2020-11-21 15:06

What is the main difference between StringBuffer and StringBuilder? Is there any performance issues when deciding on any one of these?

相关标签:
30条回答
  • 2020-11-21 15:25

    StringBuilder was introduced in Java 1.5 so it won't work with earlier JVMs.

    From the 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.

    0 讨论(0)
  • 2020-11-21 15:25

    StringBuilder (introduced in Java 5) is identical to StringBuffer, except its methods are not synchronized. This means it has better performance than the latter, but the drawback is that it is not thread-safe.

    Read tutorial for more details.

    0 讨论(0)
  • 2020-11-21 15:25

    StringBuffer is used to store character strings that will be changed (String objects cannot be changed). It automatically expands as needed. Related classes: String, CharSequence.

    StringBuilder was added in Java 5. It is identical in all respects to StringBuffer except that it is not synchronized, which means that if multiple threads are accessing it at the same time, there could be trouble. For single-threaded programs, the most common case, avoiding the overhead of synchronization makes the StringBuilder very slightly faster.

    0 讨论(0)
  • 2020-11-21 15:27

    StringBuffer

    • Synchronized hence threadsafe
    • Thread safe hence slow

    StringBuilder

    • Introduced in Java 5.0
    • Asynchronous hence fast & efficient
    • User explicitly needs to synchronize it, if he wants
    • You can replace it with StringBuffer without any other change
    0 讨论(0)
  • 2020-11-21 15:28

    Better use StringBuilder since it is not synchronized and offers therefore better performance. StringBuilder is a drop-in replacement of the older StringBuffer.

    0 讨论(0)
  • 2020-11-21 15:29

    In single threads, StringBuffer is not significantly slower than StringBuilder, thanks to JVM optimisations. And in multithreading, you can't use safely a StringBuilder.

    Here is my test (not a benchmark, just a test) :

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

    Results :
    strings: 319740
    Buffers : 23
    Builder : 7 !

    So Builders are faster than Buffers, and WAY faster than strings concatenation. Now let's use an Executor for multiple threads :

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

    Now StringBuffers take 157 ms for 100000 appends. It's not the same test, but compared to the previous 37 ms, you can safely assume that StringBuffers appends are slower with multithreading use. The reason is that the JIT/hotspot/compiler/something makes optimizations when it detects that there is no need for checking locks.

    But with StringBuilder, you have java.lang.ArrayIndexOutOfBoundsException, because a concurrent thread tries to add something where it should not.

    Conclusion is that you don't have to chase StringBuffers. And where you have threads, think about what they are doing, before trying to gain a few nanoseconds.

    0 讨论(0)
提交回复
热议问题