Câu hỏi Sự khác biệt giữa StringBuilder và StringBuffer


Sự khác biệt chính giữa StringBuffer và StringBuilder? Có bất kỳ vấn đề hiệu suất nào khi quyết định bất kỳ vấn đề nào trong số này không?


1323
2017-12-10 04:34


gốc


Kiểm tra bài viết này: StringBuilder và StringBuffer - Hussein Terek


Các câu trả lời:


StringBuffer được đồng bộ hóa, StringBuilder không phải là.


1452
2017-12-10 04:36



và StringBuilder được dùng để thay thế cho StringBuffer khi không yêu cầu đồng bộ hóa - Joel
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 một StringBuilder, họ chỉ có thể bao quanh toàn bộ khối mã với một đồng bộ (sb) {} trên cá thể - locka
@locka Tôi sẽ cho rằng StringBuffer không bao giờ là một ý tưởng hay (trừ khi bạn có một API yêu cầu nó) vanillajava.blogspot.de/2013/04/… - Peter Lawrey
Chỉ nơi tôi thấy cho một StringBuffer là giao diện điều khiển giống 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ị trộn lẫn ... nhưng thường đồng bộ hóa ở mức StringBuffer là quá thấp, bạn sẽ muốn đồng bộ hóa ở một appender như levelm nên câu trả lời locka là tốt nhất và StringBuffer sẽ không được dùng nữa. Nó sẽ tiết kiệm thời gian xem xét mã với người mới. - Remi Morin
Nghiêm túc cho những người kết hợp cả hai - BuFFer là lần đầu tiên, cũ hơn và do đó thực hiện đồng bộ. Lớp Builder mới sử dụng mẫu Builder và không đồng bộ. - Datageek


StringBuilder nhanh hơn StringBuffer bởi vì nó không synchronized.

Đây là 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);
        }
    }
}

A chạy thử nghiệm cho số lượng 2241 ms cho StringBuffer so với 753 ms cho StringBuilder.


664
2018-05-05 09:15



Tôi đã thay đổi chuỗi chữ thành một cái gì đó lớn hơn: "con cáo màu nâu nhanh" và có kết quả thú vị hơn. Về cơ bản, họ là về nhanh. 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 điểm phát sóng. Về cơ bản, bạn chỉ cần đo thời gian cần có điểm phát sóng để thực hiện việc này (và có thể một số tối ưu hóa khác). - Jilles van Gurp
Bạn cần phải làm ấm trước. Thử nghiệm này không công bằng với StringBuffer. Ngoài ra, nó sẽ là tốt nếu nó thực sự nối một cái gì đó. Trên thực tế, tôi lật thử nghiệm, và nối thêm 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, StringBuffer nhanh hơn. 5164 cho StringBuilder và 3699 cho StringBuffer hastebin.com/piwicifami.avrasm - momo
Đây là lần đầu tiên tôi nhìn thấy --> 0 trong một vòng lặp. Đã cho tôi một chút thời gian để nhận ra ý nghĩa của nó. Đây có phải là thứ thực sự được sử dụng trong thực tế thay vì thông thường không ...; i > 0; i-- cú pháp? - Raimund Krämer
Cái đó i --> thực sự gây khó chịu về cú pháp ... Tôi nghĩ đây là mũi tên lúc đầu vì những nhận xét về nghệ thuật ASCII. - Sameer Puri
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-stringbuffer-stringbuilder.html. Điểm chuẩn nên thực sự được thực hiện với JMH, không phải đơ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ự ấm lên. - Lukas Eder


Về cơ bản, StringBuffer phương pháp được đồng bộ hóa trong khi StringBuilder không.

Các hoạt động "gần như" giống nhau, nhưng việc sử dụng các phương thức đồng bộ trong một luồng đơn 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 một 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ế drop-in cho StringBuffer ở những nơi mà bộ đệm chuỗi đang được sử dụng bởi một luồng đơn (như thường là trường hợp). Nếu có thể, bạn nên sử dụng lớp này để ưu tiên StringBuffer 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 Vector và ArrayList.


228
2017-12-10 04:37



Cùng với Hashtable và HashMap. - shmosel


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 StringBuilder trừ khi bạn thực sự đang cố gắng chia sẻ một bộ đệm giữa các luồng. StringBuilder là em trai không đồng bộ (ít chi phí = hiệu quả hơn) của đồng bộ gốc StringBuffer lớp học.


151
2018-01-25 12:30



Câu trả lời tốt đầu tiên !! Vấn đề là "trừ khi bạn đang chia sẻ một bộ đệm giữa các chủ đề" - AlexWien


Đầu tiên cho phép xem điểm tương đồng: Cả hai StringBuilder và StringBuffer đều có thể thay đổi được. Đ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ộ (đồng bộ): Khi một số điều được đồng bộ hóa, thì 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ụ nào. StringBuffer được đồng bộ hóa, vì vậy bạn có thể sử dụng nó với nhiều luồng với bất kỳ vấn đề nào.

Mà một trong những sử dụng khi nào? StringBuilder: Khi bạn cần một chuỗi, có thể được sửa đổi, và chỉ có một luồng truy cập và sửa đổi nó. StringBuffer: Khi bạn cần một chuỗi, có thể được sửa đổi, và nhiều chủ đề đang truy cập và sửa đổi nó.

chú thích : Không sử dụng StringBuffer 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 nó bởi vì nó có nhiều khóa và mở khóa mã để đồng bộ hóa sẽ không cần thiết mất thời gian CPU. Không sử dụng khóa trừ khi nó được yêu cầu.


74
2017-12-11 07:11



Chỉ muốn đề cập đến các cuộc gọi phương thức INDIVIDUAL của StringBuffer là an toàn luồng. 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ư thường lệ ...). Về cơ bản, không chỉ giả định rằng bằng cách sử dụng một thư viện thread-an toàn ngay lập tức đảm bảo thread-an toàn trong chương trình CỦA BẠN! - Kevin Lee


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

Đây là bài kiểm tra của tôi:

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

Các kết quả :
chuỗi: 319740
Bộ đệm: 23
Trình tạo: 7!

Vì vậy, các nhà xây dựng nhanh hơn Buffers, và WAY nhanh hơn so với chuỗi nối. Bây giờ hãy sử dụng một Công tố viên cho nhiều chủ đề:

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 mili giây cho 100000 phụ thêm. Nó 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 StringBuffers gắn thêm chậm hơn với việc sử dụng đa luồng. Lý do là JIT / hotspot / compiler / một cái gì đó làm cho tối ưu hóa khi nó phát hiện rằng có Không cần kiểm tra khóa.

Nhưng với StringBuilder, bạn có java.lang.ArrayIndexOutOfBoundsException, bởi vì một chuỗi đồng thời cố gắng thêm một cái gì đó mà nó 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.


42
2017-11-15 16:20



Bạn đã quên làm "t0 = System.currentTimeMillis ();" trước khi thực hiện kiểm tra StringBuilder. Vì vậy, hình được hiển thị cho StringBuilder thực sự là thời gian để chạy thử nghiệm stringbuffer AND stringbuilder. Thêm dòng này và bạn sẽ thấy rằng StringBuilder IS nhanh hơn khoảng HAI TIMES. - Gena Batsyan
Sửa chữa, cảm ơn. Rõ ràng, nó thay đổi công cụ. - Nicolas Zozol
Lưu ý rằng withString+="some string"+i+" ; "; không tương đương với hai vòng lặp khác và do đó không phải là so sánh công bằng. - Dave Jarvis
Chính xác, đã sửa. Chuỗi tư tưởng 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 ArrayIndexOutOfBoundsException nâng cao cho StringBuilder - Alireza Fattahi


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 một 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ế drop-in cho StringBuffer ở những nơi mà bộ đệm chuỗi đang được sử dụng bởi một luồng đơn (như thường là trường hợp). Nếu có thể, chúng tôi khuyên rằng lớp này nên được sử dụng ưu tiên cho StringBuffer vì nó sẽ nhanh hơn trong hầu hết các triển khai.


37
2017-12-10 04:38



1.4 là vào cuối cuộc sống dịch vụ của nó, vì vậy nó hầu như không đáng lo ngại về trước 1.5. - Tom Hawtin - tackline
@ tomHawtin-tackline không nhất thiết - có những sản phẩm doanh nghiệp hiện có 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 được dựa trên 1.4 và đó vẫn là rất hiện tại. - Richard Le Mesurier
Và CDC và CLDC không có StringBuilder. - Jin Kwon