Was ist der Hauptunterschied zwischen StringBuffer
und StringBuilder
? Gibt es Leistungsprobleme bei der Entscheidung für eines dieser Probleme?
Was ist der Hauptunterschied zwischen StringBuffer
und StringBuilder
? Gibt es Leistungsprobleme bei der Entscheidung für eines dieser Probleme?
Antworten:
StringBuffer
ist synchronisiert, StringBuilder
ist nicht.
StringBuilder
ist schneller als StringBuffer
weil es nicht ist synchronized
.
Hier ist ein einfacher Benchmark-Test:
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);
}
}
}
Ein Testlauf gibt die Zahlen von 2241 ms
for StringBuffer
vs 753 ms
for an StringBuilder
.
--> 0
in einer Schleife sehe . Ich brauchte einen Moment, um zu erkennen, was es bedeutet. Wird dies tatsächlich in der Praxis anstelle der üblichen ...; i > 0; i--
Syntax verwendet?
i -->
Bezug auf die Syntax ist das wirklich ärgerlich ... Ich dachte, es sei zunächst ein Pfeil, wegen der Kommentare zur ASCII-Kunst.
main()
Außerdem ist Ihr Benchmark unfair. Es gibt kein Aufwärmen.
Grundsätzlich werden StringBuffer
Methoden synchronisiert, während dies StringBuilder
nicht der Fall ist .
Die Operationen sind "fast" gleich, aber die Verwendung synchronisierter Methoden in einem einzelnen Thread ist übertrieben.
Das ist ziemlich viel.
Zitat aus der StringBuilder-API :
Diese Klasse [StringBuilder] bietet eine API, die mit StringBuffer kompatibel ist, jedoch keine Garantie für die Synchronisierung bietet . Diese Klasse ist als Drop-In-Ersatz für StringBuffer an Stellen vorgesehen, an denen der String-Puffer von einem einzelnen Thread verwendet wurde (wie dies im Allgemeinen der Fall ist). Nach Möglichkeit wird empfohlen, diese Klasse gegenüber StringBuffer zu verwenden, da sie bei den meisten Implementierungen schneller ist.
Also wurde es gemacht, um es zu ersetzen.
Das gleiche passierte mit Vector
und ArrayList
.
Hashtable
und HashMap
.
Aber müssen Sie anhand eines Beispiels den klaren Unterschied feststellen?
StringBuffer oder StringBuilder
Verwenden StringBuilder
Sie es einfach, es sei denn, Sie versuchen wirklich, einen Puffer zwischen Threads zu teilen. StringBuilder
ist der nicht synchronisierte (weniger Overhead = effizienter) jüngere Bruder der ursprünglich synchronisierten StringBuffer
Klasse.
StringBuffer
kam zuerst. Sun war unter allen Bedingungen um Korrektheit bemüht, daher wurde es synchronisiert, um es für alle Fälle threadsicher zu machen.
StringBuilder
kam später. Die meisten Verwendungszwecke StringBuffer
waren Single-Thread- Anwendungen, bei denen die Kosten für die Synchronisierung unnötig bezahlt wurden.
Da StringBuilder
ist eine Drop-in - Ersatz für StringBuffer
, ohne die Synchronisation würde es nicht zwischen irgendwelchen Beispielen Unterschiede geben.
Wenn Sie sich zu teilen zwischen Threads versuchen, können Sie verwenden StringBuffer
, aber prüfen , ob übergeordnete Synchronisation erforderlich ist , zB vielleicht anstelle von String verwenden, sollten Sie die Methoden synchronisieren , die die Stringbuilder verwenden.
Lassen Sie uns zunächst die Ähnlichkeiten sehen : Sowohl StringBuilder als auch StringBuffer sind veränderbar. Das heißt, Sie können den Inhalt an derselben Stelle ändern.
Unterschiede : StringBuffer ist auch veränderbar und synchronisiert. Wobei as StringBuilder veränderbar, aber standardmäßig nicht synchronisiert ist.
Bedeutung von synchronisiert (Synchronisation) : Wenn etwas synchronisiert ist, können mehrere Threads darauf zugreifen und es ohne Probleme oder Nebenwirkungen ändern. StringBuffer ist synchronisiert, sodass Sie es problemlos mit mehreren Threads verwenden können.
Welches wann verwenden? StringBuilder: Wenn Sie einen String benötigen, der geändert werden kann und nur ein Thread darauf zugreift und ihn ändert. StringBuffer: Wenn Sie einen String benötigen, der geändert werden kann, und mehrere Threads darauf zugreifen und ihn ändern.
Hinweis : Verwenden Sie StringBuffer nicht unnötig, dh verwenden Sie ihn nicht, wenn nur ein Thread ihn ändert und darauf zugreift, da er viel Code zum Sperren und Entsperren für die Synchronisierung enthält, der unnötig CPU-Zeit in Anspruch nimmt. Verwenden Sie keine Schlösser, es sei denn, dies ist erforderlich.
In einzelnen Threads ist StringBuffer dank JVM-Optimierungen nicht wesentlich langsamer als StringBuilder . Und beim Multithreading können Sie einen StringBuilder nicht sicher verwenden.
Hier ist mein Test (kein Benchmark, nur ein 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));
}
Ergebnisse:
Strings: 319740
Puffer: 23
Builder: 7!
Builder sind also schneller als Puffer und viel schneller als die Verkettung von Zeichenfolgen. Verwenden wir nun einen Executor für mehrere 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);
}
}
Jetzt benötigen StringBuffers 157 ms für 100000 Anhänge. Es ist nicht der gleiche Test, aber im Vergleich zu den vorherigen 37 ms können Sie davon ausgehen, dass die Anhänge von StringBuffers bei Verwendung von Multithreading langsamer sind . Der Grund dafür ist, dass JIT / Hotspot / Compiler / Something Optimierungen vornimmt, wenn festgestellt wird, dass keine Überprüfung der Sperren erforderlich ist.
Aber mit StringBuilder haben Sie java.lang.ArrayIndexOutOfBoundsException , weil ein gleichzeitiger Thread versucht, etwas hinzuzufügen, wo es nicht sollte.
Fazit ist, dass Sie StringBuffers nicht verfolgen müssen. Und wo Sie Threads haben, überlegen Sie, was sie tun, bevor Sie versuchen, ein paar Nanosekunden zu gewinnen.
withString+="some string"+i+" ; ";
nicht den beiden anderen Schleifen entspricht und daher kein fairer Vergleich ist.
StringBuilder wurde in Java 1.5 eingeführt, sodass es mit früheren JVMs nicht funktioniert.
Aus den Javadocs :
Die StringBuilder-Klasse bietet eine API, die mit StringBuffer kompatibel ist, jedoch keine Garantie für die Synchronisierung bietet. Diese Klasse ist als Drop-In-Ersatz für StringBuffer an Stellen vorgesehen, an denen der String-Puffer von einem einzelnen Thread verwendet wurde (wie dies im Allgemeinen der Fall ist). Nach Möglichkeit wird empfohlen, diese Klasse gegenüber StringBuffer zu verwenden, da sie bei den meisten Implementierungen schneller ist.
StringBuilder
.
Ziemlich gute Frage
Hier sind die Unterschiede, die ich bemerkt habe:
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.
Verbreitete Sache :-
Beide haben dieselben Methoden mit denselben Signaturen. Beide sind veränderlich.
StringBuffer
StringBuilder
StringBuffer
ohne weitere Änderungenappend
zweimal, oder append
und toString
ist nicht nicht sicher.
StringBuilder
und StringBuffer
sind fast gleich. Der Unterschied ist, dass StringBuffer
synchronisiert ist und StringBuilder
nicht. Obwohl, StringBuilder
ist schneller als StringBuffer
, ist der Unterschied in der Leistung sehr gering. StringBuilder
ist der Ersatz einer SUN vonStringBuffer
. Es wird lediglich die Synchronisation aller öffentlichen Methoden vermieden. Stattdessen ist ihre Funktionalität dieselbe.
Beispiel für eine gute Verwendung:
Wenn sich Ihr Text ändern wird und von mehreren Threads verwendet wird, ist es besser, ihn zu verwenden StringBuffer
. Wenn sich Ihr Text ändern wird, aber von einem einzelnen Thread verwendet wird, verwenden Sie StringBuilder
.
StringBuffer
StringBuffer ist veränderbar, dh man kann den Wert des Objekts ändern. Das über StringBuffer erstellte Objekt wird im Heap gespeichert. StringBuffer hat die gleichen Methoden wie der StringBuilder, aber jede Methode in StringBuffer ist synchronisiert, dh StringBuffer ist threadsicher.
Aus diesem Grund können nicht zwei Threads gleichzeitig auf dieselbe Methode zugreifen. Auf jede Methode kann jeweils ein Thread zugreifen.
Thread-sicher zu sein hat jedoch auch Nachteile, da die Leistung des StringBuffer aufgrund der thread-sicheren Eigenschaft beeinträchtigt wird. Daher ist StringBuilder schneller als der StringBuffer, wenn dieselben Methoden für jede Klasse aufgerufen werden.
Der StringBuffer-Wert kann geändert werden. Dies bedeutet, dass er dem neuen Wert zugewiesen werden kann. Heutzutage ist es eine häufig gestellte Interviewfrage, die Unterschiede zwischen den oben genannten Klassen. Der String-Puffer kann mithilfe der toString () -Methode in den String konvertiert werden.
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 ist dasselbe wie der StringBuffer, dh er speichert das Objekt im Heap und kann auch geändert werden. Der Hauptunterschied zwischen StringBuffer und StringBuilder besteht darin, dass StringBuilder auch nicht threadsicher ist. StringBuilder ist schnell, da es nicht threadsicher ist.
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
Ressource: String Vs StringBuffer Vs StringBuilder
String
ist eine unveränderliche.
StringBuffer
ist veränderlich und synchronisiert.
StringBuilder
ist auch veränderlich, aber nicht synchronisiert.
Der Javadoc erklärt den Unterschied:
Diese Klasse bietet eine API, die mit StringBuffer kompatibel ist, jedoch keine Garantie für die Synchronisierung bietet. Diese Klasse ist als Drop-In-Ersatz für StringBuffer an Stellen vorgesehen, an denen der String-Puffer von einem einzelnen Thread verwendet wurde (wie dies im Allgemeinen der Fall ist). Nach Möglichkeit wird empfohlen, diese Klasse gegenüber StringBuffer zu verwenden, da sie bei den meisten Implementierungen schneller ist.
StringBuilder
(eingeführt in Java 5) ist identisch mit StringBuffer
, außer dass seine Methoden nicht synchronisiert sind. Dies bedeutet, dass es eine bessere Leistung als das letztere hat, aber der Nachteil ist, dass es nicht threadsicher ist.
Lesen Sie das Tutorial für weitere Details.
Ein einfaches Programm, das den Unterschied zwischen StringBuffer und StringBuilder veranschaulicht:
/**
* 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 wird zum Speichern von Zeichenfolgen verwendet, die geändert werden (String-Objekte können nicht geändert werden). Es wird bei Bedarf automatisch erweitert. Verwandte Klassen: String, CharSequence.
StringBuilder wurde in Java 5 hinzugefügt. Es ist in jeder Hinsicht identisch mit StringBuffer, außer dass es nicht synchronisiert ist. Wenn also mehrere Threads gleichzeitig darauf zugreifen, kann es zu Problemen kommen. Bei Single-Threaded-Programmen ist der StringBuilder der häufigste Fall, wenn der Synchronisierungsaufwand vermieden wird, der StringBuilder etwas schneller.
StringBuilder
sind normalerweise lokal für eine Methode, bei der sie nur für einen Thread sichtbar sind.
StringBuffer
ist synchronisiert, aber StringBuilder
nicht. Infolgedessen StringBuilder
ist schneller als StringBuffer
.
StringBuffer ist veränderbar. Es kann sich in Länge und Inhalt ändern. StringBuffers sind threadsicher, dh sie verfügen über synchronisierte Methoden zur Steuerung des Zugriffs, sodass jeweils nur ein Thread auf den synchronisierten Code eines StringBuffer-Objekts zugreifen kann. Daher können StringBuffer-Objekte in einer Umgebung mit mehreren Threads, in der möglicherweise mehrere Threads gleichzeitig versuchen, auf dasselbe StringBuffer-Objekt zuzugreifen, im Allgemeinen sicher verwendet werden.
StringBuilder Die StringBuilder-Klasse ist StringBuffer sehr ähnlich, außer dass ihr Zugriff nicht synchronisiert ist, sodass sie nicht threadsicher ist. Wenn Sie nicht synchronisiert sind, kann die Leistung von StringBuilder besser sein als die von StringBuffer. Wenn Sie in einer Umgebung mit einem Thread arbeiten, kann die Verwendung von StringBuilder anstelle von StringBuffer zu einer Leistungssteigerung führen. Dies gilt auch für andere Situationen, z. B. eine lokale StringBuilder-Variable (dh eine Variable innerhalb einer Methode), in der nur ein Thread auf ein StringBuilder-Objekt zugreift.
StringBuffer:
StringBuilder
String c = a + b
ist gleichbedeutend mit String c = new StringBuilder().append(a).append(b).toString()
, also ist es nicht schneller. Es ist nur , dass Sie eine neue für jede Saite assignation erstellen, während Sie nur eine haben könnte ( String d = a + b; d = d + c;
ist String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();
während StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();
würde man String Instanciation speichern).
String-Builder :
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.
String-Puffer
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
Es wird empfohlen, nach Möglichkeit StringBuilder zu verwenden, da dieser schneller als StringBuffer ist. Wenn jedoch die Thread-Sicherheit erforderlich ist, sind StringBuffer-Objekte die beste Option.
Bessere Verwendung, StringBuilder
da es nicht synchronisiert ist und daher eine bessere Leistung bietet. StringBuilder
ist ein Ersatz für die älteren StringBuffer
.
StringBu(ff|ild)er
ist das eine lokale Variable, die nur von einem einzelnen Thread verwendet wird.
Da StringBuffer
es synchronisiert ist, erfordert es einige zusätzliche Anstrengungen, daher ist es aufgrund der Leistung etwas langsamer als StringBuilder
.
Es gibt keine grundlegenden Unterschiede zwischen StringBuilder
und StringBuffer
, es gibt nur wenige Unterschiede zwischen ihnen. In StringBuffer
den Methoden werden synchronisiert. Dies bedeutet, dass jeweils nur ein Thread mit ihnen arbeiten kann. Wenn es mehr als einen Thread gibt, muss der zweite Thread warten, bis der erste beendet ist, und der dritte muss warten, bis der erste und der zweite Thread beendet sind und so weiter. Dies macht den Prozess sehr langsam und damit die Leistung im Fall vonStringBuffer
gering.
Ist andererseits StringBuilder
nicht synchronisiert. Dies bedeutet, dass mehrere Threads gleichzeitig an demselben StringBuilder
Objekt arbeiten können. Dies macht den Prozess sehr schnell und daher ist die Leistung von StringBuilder
hoch.
A String
ist ein unveränderliches Objekt, was bedeutet, dass der Wert nicht geändert werden kann, während er StringBuffer
veränderbar ist.
Das StringBuffer
ist synchronisiert und daher threadsicher, während StringBuilder
es nicht nur für Instanzen mit einem Thread geeignet ist.
Der Hauptunterschied besteht darin, dass er synchronisiert StringBuffer
ist, aber nicht. StringBuilder
Wenn Sie mehr als einen Thread verwenden müssen, wird StringBuffer empfohlen. Die Ausführungsgeschwindigkeit StringBuilder
ist jedoch schneller als StringBuffer
, da er nicht synchronisiert ist.
Überprüfen Sie die Interna der synchronisierten Append-Methode StringBuffer
und der nicht synchronisierten Append-Methode von 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;
}
Da Anhängen ist synchronized
, StringBuffer
hat Leistung Overhead im Vergleich zu StrinbBuilder
Multithreading-Szenario. Solange Sie den Puffer nicht für mehrere Threads freigeben, verwenden Sie StringBuilder
, was aufgrund des Fehlens von synchronized
Methoden zum Anhängen schnell ist .
Hier ist das Ergebnis des Leistungstests für String vs StringBuffer vs StringBuilder . Schließlich gewann StringBuilder den Test. Siehe unten für Testcode und Ergebnis.
Code :
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");
}
Ergebnis :
100000 Iteration zum Hinzufügen eines einzelnen Textes
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000 Iteration zum Hinzufügen eines einzelnen Textes
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBuffer ist synchronisiert und threadsicher, StringBuilder ist nicht synchronisiert und schneller.