Sự khác biệt giữa StringBuilder và StringBuffer


1577

Sự khác biệt chính giữa StringBuffervà là StringBuildergì? Có bất kỳ vấn đề hiệu suất khi quyết định bất kỳ một trong những vấn đề này?

Câu trả lời:


1665

StringBufferđược đồng bộ hóa, StringBuilderkhông.


239
và StringBuilder được dự định là sự thay thế cho StringBuffer khi không yêu cầu đồng bộ hóa
Joel

95
và đồng bộ hóa hầu như không bao giờ được yêu cầu. Nếu ai đó muốn đồng bộ hóa trên StringBuilder, họ chỉ có thể bao quanh toàn bộ khối mã bằng (sb) {} được đồng bộ hóa
locka

23
@locka Tôi sẽ lập luận rằng StringBuffer không bao giờ là một ý tưởng hay (trừ khi bạn có API yêu cầu nó) vanillajava.blogspot.de/2013/04/ Lỗi
Peter Lawrey

8
Nơi duy nhất tôi thấy cho StringBuffer là giao diện điều khiển như đầu ra và tiện ích ghi nhật ký khác nhau: nhiều luồng có thể xuất ra xung đột. Vì bạn không muốn 2 đầu ra bị lẫn lộn ... nhưng thường thì đồng bộ hóa ở mức StringBuffer quá thấp, nên bạn sẽ muốn đồng bộ hóa ở một ứng dụng như cấp độ, vì vậy câu trả lời của locka là tốt nhất và StringBuffer nên không được chấp nhận. Nó sẽ tiết kiệm thời gian xem xét mã với người mới.
Remi Morin

20
Ghi nhớ tốt cho những người kết hợp cả hai - BuFFer là Đầu tiên, cũ hơn và do đó thực hiện đồng bộ hóa. Lớp Builder mới hơn sử dụng mẫu Builder và không đồng bộ.
Datageek

728

StringBuildernhanh hơn StringBufferbởi vì nó không phải là synchronized.

Đây là một bài kiểm tra điểm chuẩn đơn giản:

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

Chạy thử cho số lượng 2241 msfor StringBuffervs 753 msfor StringBuilder.


10
Tôi đã thay đổi chuỗi ký tự thành một thứ lớn hơn: "con cáo nâu nhanh" và nhận được kết quả thú vị hơn. Về cơ bản, chúng là về nhanh như vậy. Tôi thực sự đã hết bộ nhớ vì vậy tôi phải loại bỏ một vài bảy. Giải thích: đồng bộ hóa được tối ưu hóa bằng hotspot. Về cơ bản, bạn chỉ đang đo thời gian cần hotspot để thực hiện việc này (và có thể là một số tối ưu hóa nữa).
Jilles van Gurp

7
Bạn cần làm nóng trước. Thử nghiệm này không công bằng với StringBuffer. Ngoài ra, nó sẽ tốt nếu nó thực sự nối thêm một cái gì đó. Trên thực tế, tôi đã lật bài kiểm tra và nối một chuỗi ngẫu nhiên và có bài kiểm tra ngược lại. Nói rằng, người ta không thể tin tưởng điểm chuẩn đơn giản. Ngược lại cho thấy StringBuffer nhanh hơn. 5164 cho StringBuilder so với 3699 cho StringBuffer hastebin.com/piwicifami.avrasm
mmm

75
Đây là lần đầu tiên tôi thấy --> 0trong một vòng lặp. Mất một lúc để nhận ra ý nghĩa của nó. Đây có phải là cái gì đó thực sự được sử dụng trong thực tế thay vì ...; i > 0; i--cú pháp thông thường ?
Raimund Krämer

19
Đó i -->thực sự là một cú pháp khó chịu ... Tôi nghĩ rằng ban đầu nó là một mũi tên vì những bình luận về nghệ thuật ASCII.
Sameer Puri

14
Những người khác kết luận với các kết quả khác nhau: alblue.bandlem.com/2016/04/jmh-opesbuffer-opesbuilder.html . Điểm chuẩn nên thực sự được thực hiện với JMH, không đơn giản main()Ngoài ra, điểm chuẩn của bạn là không công bằng. Không có sự khởi động.
Lukas Eder

249

Về cơ bản, StringBuffercác phương thức được đồng bộ hóa trong khiStringBuilder không.

Các hoạt động "gần như" giống nhau, nhưng sử dụng các phương thức được đồng bộ hóa trong một luồng duy nhất là quá mức cần thiết.

Đó là khá nhiều về nó.

Trích dẫn từ API StringBuilder :

Lớp này [StringBuilder] cung cấp API tương thích với StringBuffer, nhưng không đảm bảo đồng bộ hóa . Lớp này được thiết kế để sử dụng như là một thay thế thả xuống cho StringBuffer ở những nơi mà bộ đệm chuỗi đang được sử dụng bởi một luồng duy nhất (như thường là trường hợp). Nếu có thể, lớp này được khuyến nghị sử dụng theo ưu tiên cho StringBuffer vì nó sẽ nhanh hơn trong hầu hết các triển khai.

Vì vậy, nó đã được thực hiện để thay thế nó.

Điều tương tự cũng xảy ra với VectorArrayList.


1
Cũng với HashtableHashMap.
shmosel 17/03/2017

176

Nhưng cần thiết để có được sự khác biệt rõ ràng với sự giúp đỡ của một ví dụ?

StringBuffer hoặc StringBuilder

Đơn giản chỉ cần sử dụng StringBuildertrừ khi bạn thực sự đang cố gắng chia sẻ bộ đệm giữa các luồng. StringBuilderlà em trai không đồng bộ (ít chi phí = hiệu quả hơn) của StringBufferlớp được đồng bộ hóa ban đầu .

StringBufferđến đầu tiên. Sun quan tâm đến tính chính xác trong mọi điều kiện, vì vậy họ đã làm cho nó được đồng bộ hóa để làm cho nó an toàn chỉ trong trường hợp.

StringBuilderđến sau Hầu hết các công dụng củaStringBuffer là một luồng và trả chi phí không cần thiết cho việc đồng bộ hóa.

StringBuilderlà một thay thế thả trong choStringBuffer mà không có sự đồng bộ, sẽ không có sự khác biệt giữa bất kỳ ví dụ.

Nếu bạn đang cố gắng chia sẻ giữa các luồng, bạn có thể sử dụng StringBuffer, nhưng xem xét liệu có cần đồng bộ hóa mức cao hơn hay không, ví dụ có thể thay vì sử dụng StringBuffer, bạn có nên đồng bộ hóa các phương thức sử dụng StringBuilder hay không.


14
Câu trả lời tốt đầu tiên !! Vấn đề là "trừ khi bạn đang chia sẻ bộ đệm giữa các luồng"
AlexWien 20/03/2015

1
Câu trả lời rất chi tiết!
Raúl

81

Đầu tiên chúng ta hãy xem những điểm tương đồng : Cả StringBuilder và StringBuffer đều có thể thay đổi. Điều đó có nghĩa là bạn có thể thay đổi nội dung của chúng, với cùng một vị trí.

Sự khác biệt : StringBuffer cũng có thể thay đổi và đồng bộ hóa. Trong trường hợp StringBuilder có thể thay đổi nhưng không được đồng bộ hóa theo mặc định.

Ý nghĩa của đồng bộ hóa (đồng bộ hóa) : Khi một số thứ được đồng bộ hóa, sau đó nhiều luồng có thể truy cập và sửa đổi nó với bất kỳ vấn đề hoặc tác dụng phụ. StringBuffer được đồng bộ hóa, vì vậy bạn có thể sử dụng nó với nhiều luồng mà không gặp vấn đề gì.

Nên dùng cái nào khi nào? StringBuilder: Khi bạn cần một chuỗi, có thể sửa đổi và chỉ có một luồng đang truy cập và sửa đổi nó. StringBuffer: Khi bạn cần một chuỗi, có thể sửa đổi và nhiều luồng đang truy cập và sửa đổi nó.

Lưu ý : Không sử dụng StringBuffer một cách không cần thiết, tức là không sử dụng nó nếu chỉ có một luồng đang sửa đổi và truy cập vào nó vì nó có rất nhiều mã khóa và mở khóa để đồng bộ hóa sẽ làm mất thời gian CPU một cách không cần thiết. Đừng sử dụng ổ khóa trừ khi được yêu cầu.


2
Chỉ muốn đề cập rằng các cuộc gọi phương thức INDIVIDUAL của StringBuffer là an toàn cho chuỗi. Nhưng nếu bạn có nhiều dòng mã, hãy sử dụng khối mã được đồng bộ hóa để đảm bảo an toàn luồng, với một số khóa / màn hình (như bình thường ...). Về cơ bản, đừng chỉ cho rằng sử dụng thư viện an toàn luồng ngay lập tức đảm bảo an toàn luồng trong chương trình CỦA BẠN!
Kevin Lee

57

Trong các luồng đơn, StringBuffer không chậm hơn đáng kể so với StringBuilder , nhờ tối ưu hóa JVM. Và trong đa luồng, bạn không thể sử dụng StringBuilder một cách an toàn.

Đây là bài kiểm tra của tôi (không phải điểm chuẩn, chỉ là bài kiểm tra):

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

Kết quả:
chuỗi: 319740
Bộ đệm: 23
Builder: 7!

Vì vậy, Nhà xây dựng nhanh hơn Bộ đệm và CÁCH nhanh hơn so với nối chuỗi. Bây giờ hãy sử dụng Executor cho nhiều luồng:

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

Bây giờ StringBuffers mất 157 ms cho 100000 phụ lục. Đây không phải là thử nghiệm tương tự, nhưng so với 37 ms trước đó, bạn có thể giả định rằng các phần bổ sung StringBuffers chậm hơn khi sử dụng đa luồng . Lý do là JIT / hotspot / trình biên dịch / cái gì đó thực hiện tối ưu hóa khi phát hiện ra rằng không cần kiểm tra khóa.

Nhưng với StringBuilder, bạn có java.lang.ArrayIndexOutOfBoundException , bởi vì một luồng đồng thời cố gắng thêm một cái gì đó không nên.

Kết luận là bạn không phải đuổi theo StringBuffers. Và nơi bạn có chủ đề, hãy suy nghĩ về những gì họ đang làm, trước khi cố gắng đạt được một vài nano giây.


5
Bạn đã quên làm "t0 = System.cienTimeMillis ();" trước khi thực hiện kiểm tra StringBuilder. Vì vậy, con số hiển thị cho StringBuilder thực sự là thời gian cần thiết để chạy thử nghiệm Stringbuffer VÀ Stringbuilder. Thêm dòng này và bạn sẽ thấy StringBuilder IS nhanh hơn về HAI LẦN.
Gena Batsyan

Lưu ý rằng withString+="some string"+i+" ; ";không tương đương với hai vòng còn lại và do đó không phải là một so sánh công bằng.
Dave Jarvis

Chính xác, đã sửa. Những chuỗi suy nghĩ vẫn còn rất chậm.
Nicolas Zozol

Bạn có thể giải thích thêm lý do tại sao Array IndexOutOfBoundException tăng cho StringBuilder
Alireza Fattahi

Bạn nên sử dụng JMH cho điểm chuẩn. Điểm chuẩn của bạn thực sự không chính xác.
Lukas Eder

42

StringBuilder đã được giới thiệu trong Java 1.5 vì vậy nó sẽ không hoạt động với các JVM trước đó.

Từ Javadocs :

Lớp StringBuilder cung cấp API tương thích với StringBuffer, nhưng không đảm bảo đồng bộ hóa. Lớp này được thiết kế để sử dụng như là một thay thế thả xuống cho StringBuffer ở những nơi mà bộ đệm chuỗi đang được sử dụng bởi một luồng duy nhất (như thường là trường hợp). Nếu có thể, lớp này được khuyến nghị sử dụng theo ưu tiên cho StringBuffer vì nó sẽ nhanh hơn trong hầu hết các triển khai.


13
1.4 đã hết thời hạn sử dụng, vì vậy hầu như không đáng lo ngại về tiền 1.5.
Tom Hawtin - tackline

@ tomHawtin-tackline không nhất thiết - có những sản phẩm dành cho doanh nghiệp trên 1.4 trước mà hầu hết chúng ta sử dụng hàng ngày. Ngoài ra BlackBerry java dựa trên 1.4 và điều đó vẫn còn rất thời sự.
Richard Le Mesurier

Và CDC và CLDC không có StringBuilder.
Jin Kwon

37

Câu hỏi khá hay

Dưới đây là sự khác biệt, tôi đã nhận thấy:

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.

Điều phổ biến :-

Cả hai đều có cùng một phương pháp với chữ ký giống nhau. Cả hai đều có thể thay đổi.


23

StringBuffer

  • Đồng bộ hóa do đó chủ đề an toàn
  • Chủ đề an toàn do đó chậm

StringBuilder

  • Được giới thiệu trong Java 5.0
  • Do đó không đồng bộ nhanh và hiệu quả
  • Người dùng cần phải đồng bộ hóa nó một cách rõ ràng, nếu anh ta muốn
  • Bạn có thể thay thế nó StringBuffermà không có bất kỳ thay đổi nào khác

LƯU Ý: Chỉ các hoạt động đơn lẻ là an toàn luồng, nhiều hoạt động không. ví dụ như nếu bạn gọi appendhai lần, hay appendtoStringkhông phải là không an toàn.
Peter Lawrey

22

StringBuilder không phải là chủ đề an toàn. Chuỗi đệm là. Thêm thông tin ở đây .

EDIT: Về hiệu suất, sau khi hotspot khởi động, StringBuilder là người chiến thắng. Tuy nhiên, đối với các lần lặp nhỏ, sự khác biệt hiệu suất là không đáng kể.


21

StringBuilderStringBuffergần như giống nhau. Sự khác biệt là StringBufferđồng bộ hóa và StringBuilderkhông. Mặc dù, StringBuildernhanh hơn StringBuffer, sự khác biệt về hiệu suất là rất ít. StringBuilderlà sự thay thế của SUNStringBuffer . Nó chỉ tránh đồng bộ hóa từ tất cả các phương thức công cộng. Thay vào đó, chức năng của chúng là như nhau.

Ví dụ về cách sử dụng tốt:

Nếu văn bản của bạn sẽ thay đổi và được sử dụng bởi nhiều chủ đề, thì tốt hơn là sử dụng StringBuffer. Nếu văn bản của bạn sẽ thay đổi nhưng được sử dụng bởi một chủ đề, sau đó sử dụng StringBuilder.


19

StringBuffer

StringBuffer có thể thay đổi có nghĩa là người ta có thể thay đổi giá trị của đối tượng. Đối tượng được tạo thông qua StringBuffer được lưu trữ trong heap. StringBuffer có cùng các phương thức với StringBuilder, nhưng mỗi phương thức trong StringBuffer được đồng bộ hóa là StringBuffer là luồng an toàn.

bởi vì điều này không cho phép hai luồng truy cập cùng một phương thức. Mỗi phương thức có thể được truy cập bởi một luồng tại một thời điểm.

Nhưng việc bảo mật luồng cũng có nhược điểm vì hiệu suất của các lần truy cập StringBuffer do thuộc tính an toàn của luồng. Do đó, StringBuilder nhanh hơn StringBuffer khi gọi các phương thức giống nhau của mỗi lớp.

Giá trị StringBuffer có thể được thay đổi, điều đó có nghĩa là nó có thể được gán cho giá trị mới. Ngày nay, đây là một câu hỏi phỏng vấn phổ biến nhất, sự khác biệt giữa các lớp trên. Chuỗi đệm có thể được chuyển đổi thành chuỗi bằng cách sử dụng phương thức 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 giống như StringBuffer, nghĩa là nó lưu trữ đối tượng trong heap và nó cũng có thể được sửa đổi. Sự khác biệt chính giữa StringBuffer và StringBuilder là StringBuilder cũng không an toàn cho chuỗi. StringBuilder nhanh vì nó không phải là chủ đề an toàn.

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

nhập mô tả hình ảnh ở đây

Tài nguyên: Chuỗi Vs StringBuffer Vs StringBuilder


StringBuilder là bất biến và Kiểu chuỗi có thể thay đổi
Brinda Rathod

Tôi không đồng ý rằng String và StringBuilders "nhanh" và StringBuffers "rất chậm". Xem các câu trả lời trên.
FireCubez

17

String là một bất biến.

StringBuffer là một đột biến và đồng bộ.

StringBuilder cũng có thể thay đổi nhưng nó không được đồng bộ hóa.


Ngoài ra, StringBuffer khóa Chủ đề để truy cập chủ đề này dữ liệu an toàn, đó là lý do tại sao hoạt động chậm. StringBuilder không khóa luồng và nó chạy theo cách Đa luồng, đó là lý do tại sao nhanh. Chuỗi - khi bạn không cần nối chuỗi thì đây là cách tốt, nhưng khi bạn cần sử dụng StringBuilder -> vì String tạo ra mỗi khi đối tượng mới trong heap, nhưng StringBuilder trả về cùng một đối tượng ...
Musa

11

Các javadoc giải thích sự khác biệt:

Lớp này cung cấp API tương thích với StringBuffer, nhưng không đảm bảo đồng bộ hóa. Lớp này được thiết kế để sử dụng như là một thay thế thả xuống cho StringBuffer ở những nơi mà bộ đệm chuỗi đang được sử dụng bởi một luồng duy nhất (như thường là trường hợp). Nếu có thể, lớp này được khuyến nghị sử dụng theo ưu tiên cho StringBuffer vì nó sẽ nhanh hơn trong hầu hết các triển khai.


10

StringBuilder(được giới thiệu trong Java 5) giống hệt với StringBuffer, ngoại trừ các phương thức của nó không được đồng bộ hóa. Điều này có nghĩa là nó có hiệu suất tốt hơn cái sau, nhưng nhược điểm là nó không an toàn cho chủ đề.

Đọc hướng dẫn để biết thêm chi tiết.


6

Một chương trình đơn giản minh họa sự khác biệt giữa StringBuffer và 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");
        }

    }
}

4

StringBuffer được sử dụng để lưu trữ các chuỗi ký tự sẽ được thay đổi (Các đối tượng chuỗi không thể thay đổi). Nó tự động mở rộng khi cần thiết. Các lớp liên quan: Chuỗi, CharSequence.

StringBuilder đã được thêm vào trong Java 5. Nó giống hệt nhau về mọi khía cạnh với StringBuffer ngoại trừ việc nó không được đồng bộ hóa, điều đó có nghĩa là nếu nhiều luồng đang truy cập cùng một lúc, có thể có sự cố. Đối với các chương trình đơn luồng, trường hợp phổ biến nhất, tránh chi phí đồng bộ hóa khiến StringBuilder nhanh hơn một chút.


4
Các chương trình đơn luồng không phải là trường hợp phổ biến nhất trong Java, nhưng StringBuilderare thường là cục bộ của một phương thức, trong đó chúng chỉ hiển thị với một luồng.
vây

4

StringBufferđược đồng bộ hóa, nhưng StringBuilderkhông phải. Kết quả StringBuilderlà nhanh hơn StringBuffer.


4

StringBuffer có thể thay đổi. Nó có thể thay đổi về chiều dài và nội dung. StringBuffers an toàn cho luồng, nghĩa là chúng có các phương thức được đồng bộ hóa để kiểm soát truy cập để chỉ một luồng có thể truy cập mã được đồng bộ hóa của đối tượng StringBuffer tại một thời điểm. Do đó, các đối tượng StringBuffer thường an toàn để sử dụng trong môi trường đa luồng trong đó nhiều luồng có thể đang cố gắng truy cập cùng một đối tượng StringBuffer cùng một lúc.

StringBuilder Lớp StringBuilder rất giống với StringBuffer, ngoại trừ việc truy cập của nó không được đồng bộ hóa để nó không an toàn cho luồng. Bằng cách không được đồng bộ hóa, hiệu suất của StringBuilder có thể tốt hơn StringBuffer. Do đó, nếu bạn đang làm việc trong môi trường đơn luồng, sử dụng StringBuilder thay vì StringBuffer có thể dẫn đến hiệu suất tăng. Điều này cũng đúng với các tình huống khác, chẳng hạn như biến cục bộ StringBuilder (nghĩa là một biến trong một phương thức) trong đó chỉ có một luồng sẽ truy cập vào một đối tượng StringBuilder.


4

StringBuffer:

  • Đa chủ đề
  • Đã đồng bộ hóa
  • Chậm hơn StringBuilder

StringBuilder

  • Chủ đề đơn
  • Không đồng bộ hóa
  • Chuỗi nhanh hơn bao giờ hết

2
Chính xác hơn, String c = a + btương đương với String c = new StringBuilder().append(a).append(b).toString(), vì vậy nó không nhanh hơn. Đó là duy nhất mà bạn tạo một hình mới cho mỗi gán chuỗi, trong khi bạn có thể chỉ có một ( String d = a + b; d = d + c;String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();thời gian StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();sẽ tiết kiệm một StringBuilder instanciation).
Chặt

4

Trình tạo chuỗi :

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.

Bộ đệm chuỗi

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

Bạn nên sử dụng StringBuilder bất cứ khi nào có thể vì nó nhanh hơn StringBuffer. Tuy nhiên, nếu sự an toàn của luồng là cần thiết, tùy chọn tốt nhất là các đối tượng StringBuffer.


Nếu bạn cần an toàn luồng, tùy chọn tốt nhất là sử dụng StringBuilder vì StringBuffer chỉ là luồng an toàn cho các hoạt động riêng lẻ. Đối với nhiều hoạt động, bạn cần khóa rõ ràng.
Peter Lawrey

4

Sử dụng tốt hơn StringBuildervì nó không được đồng bộ hóa và do đó hiệu suất tốt hơn. StringBuilderlà một sự thay thế thả xuống của cái cũ StringBuffer.


3
@Mark đúng nhưng hầu hết thời gian StringBu(ff|ild)erlà một biến cục bộ chỉ được sử dụng bởi một luồng duy nhất.
gabuzo

1
@MarkMcKenna: Ngay cả trong một ứng dụng đa luồng, người ta thường sẽ phải sử dụng khóa ngoài hoặc làm thêm để tránh nó. Ví dụ: nếu hai luồng mỗi luồng muốn nối một bản ghi chứa nhiều chuỗi vào trình tạo chuỗi, chúng sẽ phải tổng hợp dữ liệu cần thêm và sau đó thêm nó dưới dạng một đơn vị ngay cả khi nó nhanh hơn - các vấn đề luồng vắng mặt-- để đơn giản thực hiện một chuỗi các hoạt động chắp thêm rời rạc.
supercat

3

StringBufferđược đồng bộ hóa, nó cần một số nỗ lực bổ sung, do đó dựa trên độ đục lỗ, nó hơi chậm hơn StringBuilder.


3

Không có sự khác biệt cơ bản giữa StringBuilderStringBuffer, chỉ có một vài khác biệt tồn tại giữa chúng. Trong StringBuffercác phương pháp được đồng bộ hóa. Điều này có nghĩa là tại một thời điểm chỉ có một luồng có thể hoạt động trên chúng. Nếu có nhiều hơn một luồng thì luồng thứ hai sẽ phải đợi cho chuỗi đầu tiên kết thúc và luồng thứ ba sẽ phải đợi cho chuỗi đầu tiên và thứ hai kết thúc, v.v. Điều này làm cho quá trình rất chậm và do đó hiệu suất trong trường hợp StringBufferthấp.

Mặt khác, StringBuilderkhông được đồng bộ hóa. Điều này có nghĩa là tại một thời điểm, nhiều luồng có thể hoạt động trên cùng một StringBuilderđối tượng cùng một lúc. Điều này làm cho quá trình rất nhanh và do đó hiệu suất StringBuildercao.


3

A Stringlà một đối tượng bất biến có nghĩa là giá trị không thể thay đổi trong khi StringBuffercó thể thay đổi.

Các StringBufferđược đồng bộ do đó thread-safe trong khi StringBuilderkhông phù hợp và chỉ dành cho trường hợp đơn luồng.


3
chỉ vì StringBuffer có mã được đồng bộ hóa, không nhất thiết có nghĩa là StringBuffer là chủ đề an toàn. Xem xét ví dụ sau: StringBuffer testsBuffer = "stackoverflow"; Bây giờ Thread-1 đang cố nối thêm "1" vào testsBuffer và Thread-2 đang cố nối thêm "2" vào testBuffer. Bây giờ mặc dù phương thức append () đã được đồng bộ hóa, bạn không thể chắc chắn giá trị của testsBuffer sẽ là "stackoverflow12" hay "stackoverflow21". Trên thực tế, Oracle khuyên nên sử dụng Stringbuilder hơn Stringbuffer. Tôi hy vọng điều này có ích :)
Biman Tripathy 25/12/12

2

Sự khác biệt chính là StringBufferđược đồng bộ hóa nhưng StringBuilderkhông. Nếu bạn cần sử dụng nhiều hơn một luồng, thì StringBuffer được khuyến nghị. Nhưng, vì tốc độ thực thi StringBuildernhanh hơn StringBuffer, vì nó không được đồng bộ hóa.


4
StringBuffer chỉ là luồng an toàn nếu bạn thực hiện chỉ một thao tác trên nó. Tôi không khuyên bạn nên sử dụng nó trong nhiều luồng vì rất khó để lấy đúng.
Peter Lawrey 17/12/13

@PeterLawrey nghĩa là gì? :-)
Tamad Lang

1
@ b16db0 Ý tôi là hầu hết việc sử dụng StringBuffer không phải là luồng an toàn vì chúng thực hiện nhiều cuộc gọi đến nó mà không đồng bộ hóa bên ngoài, làm cho lớp trở nên vô nghĩa.
Peter Lawrey

@PeterLawrey ah giống như StringBuffer vẫn cần một môi trường đồng bộ.
Tamad Lang

2

Kiểm tra phần bên trong của phương thức chắp thêm được đồng bộ hóa và phương pháp chắp thêm StringBufferkhông đồng bộ của 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;
}

Vì append là synchronized, StringBuffercó hiệu năng vượt trội so với StrinbBuildertrong kịch bản đa luồng. Miễn là bạn không chia sẻ bộ đệm giữa nhiều luồng, hãy sử dụng StringBuilder, nhanh, do không có synchronizedtrong các phương thức chắp thêm.


1

Dưới đây là kết quả kiểm tra hiệu năng cho String vs StringBuffer vs StringBuilder . Cuối cùng, StringBuilder đã thắng Bài kiểm tra. Xem dưới đây để kiểm tra mã và kết quả.

Mã số :

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

  }

Thực thi tôi trên ideone

Kết quả :

100000 lần lặp để thêm một văn bản

String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms

10000 lần lặp để thêm một văn bản

String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms

1
  • StringBuffer là luồng an toàn nhưng StringBuilder không phải là luồng an toàn.
  • StringBuilder nhanh hơn StringBuffer.
  • StringBuffer được đồng bộ hóa trong khi StringBuilder không được đồng bộ hóa.

1

StringBuffer được đồng bộ hóa và luồng an toàn, StringBuilder không được đồng bộ hóa và nhanh hơn.


Sự khác biệt này đã được đưa ra trong tất cả các câu trả lời khác cho câu hỏi này. Bạn có thể làm nổi bật một cái gì đó mới?
Nico Haase
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.