In dieses Beispiel , StringBuffer ist eigentlich schneller als StringBuilder, während ich gegenteilige Ergebnisse erwartet hätte.
Hat das etwas mit Optimierungen zu tun, die vom JIT gemacht werden? Weiß jemand, warum StringBuffer schneller als StringBuilder wäre, obwohl seine Methoden synchronisiert sind?
Hier ist der Code und die Benchmark-Ergebnisse:
%Vor%
Benchmark-Ergebnisse:
UPDATE:
Danke an alle. Warmup war in der Tat das Problem. Sobald ein Warmup-Code hinzugefügt wurde, wurden die Benchmarks folgendermaßen geändert:
%Vor%
YMMV, aber zumindest stimmen die Gesamtquoten mit dem überein, was zu erwarten wäre.
Ich habe mir Ihren Code angesehen, und der wahrscheinlichste Grund dafür, dass StringBuilder
it langsamer erscheint, ist, dass Ihr Benchmark die Auswirkungen von JVM-Aufwärmen nicht richtig berücksichtigt. In diesem Fall:
Einer oder beide können zu der Zeit addiert werden, die für den StringBuilder
-Teil Ihres Tests gemessen wurde.
Bitte lesen Sie die Antworten zu dieser Frage für weitere Details: Wie schreibe ich einen korrekten Mikro-Benchmark in Java?
In beiden Fällen wird der exakt gleiche Code aus java.lang.AbstractStringBuilder
verwendet, und beide Instanzen werden mit derselben Kapazität (16) erstellt.
Der einzige Unterschied ist die Verwendung von synchronized
beim ersten Aufruf.
Ich schließe, das ist ein Messartefakt.
StringBuilder:
%Vor%StringBuffer:
%Vor%AbstractStringBuilder:
%Vor%(expandCapacity ist nicht überschrieben)
Dieser Blogbeitrag sagt mehr über:
Beachten Sie, dass die "Langsamkeit" von synchronisiert in der letzten JDK als ein Mythos betrachtet werden kann. Alle Tests, die ich gemacht oder gelesen habe, schlussfolgern, dass es im Allgemeinen keinen Grund gibt, viel Zeit zu verlieren, um die Synchronisationen zu vermeiden.
Wenn Sie diesen Code auf sich selbst ausführen, würden Sie ein unterschiedliches Ergebnis sehen. Manchmal ist StringBuffer schneller und manchmal ist StringBuilder schneller.
Der wahrscheinlichste Grund hierfür könnte die Zeit sein, die für JVM warmup
benötigt wird, bevor% StringBuffer
und StringBuilder
wie von @ Stephen angegeben verwendet wird, was bei mehreren Läufen variieren kann.
Dies ist das Ergebnis von 4 Läufen, die ich gemacht habe: -
%Vor%Natürlich können die genauen Zahlen nicht anhand von nur 4 Ausführungen vorhergesagt werden.
Ich schlage vor
Wenn Sie Code weniger als 10000 Mal ausführen, löst dies möglicherweise nicht aus, dass der Code als Standardcode -XX:CompileThreshold=10000
kompiliert wird. Ein Teil des Grundes ist es, Statistiken darüber zu sammeln, wie der Code am besten zu optimieren ist. Wenn eine Schleife jedoch die Kompilierung auslöst, wird sie für die ganze Methode ausgelöst, wodurch spätere Schleifen entweder a) besser aussehen, wenn sie kompiliert werden, bevor sie beginnen, b) schlimmer, wenn sie kompiliert werden, ohne Statistiken zu sammeln .
Betrachten Sie den folgenden Code
%Vor%druckt mit Läufen = 1000
%Vor%jedoch, wenn Sie die Anzahl der Läufe = 10.000
erhöhen %Vor%und wenn wir die Läufe auf 100.000 erhöhen, bekomme ich
%Vor% Hinweis: Die +
-Operation hat sich verlangsamt, da die Zeitkomplexität der Schleife O (N ^ 2)
Ich habe deinen Code ein wenig modifiziert und die Aufwärmschleifen hinzugefügt. Meine Beobachtungen sind die meiste Zeit konsistent, dass StringBuilder meistens schneller ist.
Ich benutze die Ubuntu12.04-Box, die virtuell auf Windows 7 läuft und der VM 2 GB RAM zugewiesen hat.
%Vor%}
Ergebnisse sind:
%Vor%Tags und Links java stringbuilder stringbuffer