Câu trả lời:
StringBuffer
được đồng bộ hóa, StringBuilder
không.
StringBuilder
nhanh hơn StringBuffer
bở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 ms
for StringBuffer
vs 753 ms
for StringBuilder
.
--> 0
trong 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 ?
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.
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.
Về cơ bản, StringBuffer
cá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 Vector
và ArrayList
.
Hashtable
và HashMap
.
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ẻ 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 StringBuffer
lớ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.
Vì StringBuilder
là 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.
Đầ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.
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.
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.
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.
StringBuilder
.
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.
StringBuffer
StringBuilder
StringBuffer
mà không có bất kỳ thay đổi nào khácappend
hai lần, hay append
và toString
không phải là không an toàn.
StringBuilder
và StringBuffer
gần như giống nhau. Sự khác biệt là StringBuffer
đồng bộ hóa và StringBuilder
không. Mặc dù, StringBuilder
nhanh hơn StringBuffer
, sự khác biệt về hiệu suất là rất ít. StringBuilder
là 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
.
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
Tài nguyên: Chuỗi Vs StringBuffer Vs StringBuilder
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.
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.
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.
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");
}
}
}
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.
StringBuilder
are 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.
StringBuffer
được đồng bộ hóa, nhưng StringBuilder
không phải. Kết quả StringBuilder
là nhanh hơn StringBuffer
.
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.
StringBuffer:
StringBuilder
String c = a + b
tươ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;
là 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).
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.
Sử dụng tốt hơn StringBuilder
vì nó không được đồng bộ hóa và do đó hiệu suất tốt hơn. StringBuilder
là một sự thay thế thả xuống của cái cũ StringBuffer
.
StringBu(ff|ild)er
là một biến cục bộ chỉ được sử dụng bởi một luồng duy nhất.
Vì 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
.
Không có sự khác biệt cơ bản giữa StringBuilder
và StringBuffer
, chỉ có một vài khác biệt tồn tại giữa chúng. Trong StringBuffer
cá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 StringBuffer
thấp.
Mặt khác, StringBuilder
khô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 StringBuilder
cao.
A String
là một đối tượng bất biến có nghĩa là giá trị không thể thay đổi trong khi StringBuffer
có thể thay đổi.
Các StringBuffer
được đồng bộ do đó thread-safe trong khi StringBuilder
không phù hợp và chỉ dành cho trường hợp đơn luồng.
Sự khác biệt chính là StringBuffer
được đồng bộ hóa nhưng StringBuilder
khô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 StringBuilder
nhanh hơn StringBuffer
, vì nó không được đồng bộ hóa.
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 StringBuffer
không đồng bộ của 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;
}
Vì append là synchronized
, StringBuffer
có hiệu năng vượt trội so với StrinbBuilder
trong 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ó synchronized
trong các phương thức chắp thêm.
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");
}
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
StringBuffer được đồng bộ hóa và luồng an toàn, StringBuilder không được đồng bộ hóa và nhanh hơn.