Angenommen, es gibt eine Zeichenfolge. Wir werden viele Schleifenspleißoperationen für diese Zeichenfolge durchführen. Die Verwendung von „+“ erzielt die niedrigste Leistung. Aber wie schlecht ist diese Leistung? Was wäre das Ergebnis, wenn wir auch StringBuffer, StringBuilder oder String.concat() in den Leistungstest einbeziehen würden? Dieser Artikel gibt eine Antwort auf diese Fragen!
Wir werden Per4j verwenden, um die Leistung zu berechnen, da dieses Tool uns einen vollständigen Satz von Leistungsindikatoren liefern kann, wie z. B. die minimale und maximale benötigte Zeit, die Standardabweichung des statistischen Zeitraums usw. Um im Testcode einen genauen Standardabweichungswert zu erhalten, führen wir einen Test mit 20 Spleißungen „*“ 50.000 Mal durch. Hier ist die Methode, die wir zum Verketten von Zeichenfolgen verwenden werden:
Kopieren Sie den Codecode wie folgt:
Verkettungsoperator (+)
String-Concat-Methode concat(String str)
StringBuffer-Anhängemethode append(String str)
StringBuilder-Anhängemethode append(String str)
Abschließend schauen wir uns den Bytecode an, um zu sehen, wie genau diese Methoden ausgeführt werden. Beginnen wir nun mit der Erstellung unserer Klasse. Beachten Sie, dass zur Berechnung der Leistung jeder Schleife jeder Testcode im Code mit der Per4J-Bibliothek umschlossen werden muss. Zuerst definieren wir die Anzahl der Iterationen
Kopieren Sie den Codecode wie folgt:
privates statisches final int OUTER_ITERATION=20;
private static final int INNER_ITERATION=50000;
Als nächstes werden wir die oben genannten 4 Methoden verwenden, um unseren Testcode zu implementieren.
Kopieren Sie den Codecode wie folgt:
String addTestStr = "";
String concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
addTestStr = "";
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
addTestStr += "*";
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringConcat");
concatTestStr = "";
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestStr.concat("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
concatTestSb = new StringBuffer();
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
concatTestSbu = new StringBuilder();
for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
stopWatch.stop();
}
Führen Sie als Nächstes das Programm aus, um Leistungsmetriken zu generieren. Meine Betriebsumgebung ist ein 64-Bit-Windows 7-Betriebssystem, eine 32-Bit-JVM-Maschine (7-ea) mit 4 GB Speicher und einer Dual-Core-Quad-CPU mit 2,00 GHz.
Es ist genau so geworden, wie wir es uns vorgestellt haben. Das einzig Interessante ist, warum String.concat auch sehr gut ist. Wir alle wissen, dass String eine konstante Klasse ist (eine Klasse, die sich nach der Initialisierung nicht ändert). Warum ist die Leistung von concat also besser? (Anmerkung des Übersetzers: Tatsächlich liegt ein Problem mit dem Testcode des ursprünglichen Autors vor. Der Testcode für die concat()-Methode sollte als concatTestStr=concatTestStr.concat(“*”) geschrieben werden.) Um dies zu beantworten Frage, wir sollten uns die Concat-Dekompilierung ansehen. Der Bytecode kommt heraus. Das Download-Paket dieses Artikels enthält alle Bytecodes, aber jetzt werfen wir einen Blick auf diesen Codeausschnitt von concat:
Kopieren Sie den Codecode wie folgt:
46: new #6; //class java/lang/StringBuilder
49: dup
50: invokespecial #7; //Methode java/lang/StringBuilder."<init>":()V
53: aload_1
54: invokevirtual #8; //Methode java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: ldc #9; //String *
59: invokevirtual #8; //Methode java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
62: invokevirtual #10; //Methode java/lang/StringBuilder.toString:()
Ljava/lang/String;
65: astore_1
66: iinc 7, 1
69: gehe zu 38
Dieser Code ist der Bytecode von String.concat(). Aus diesem Code können wir deutlich erkennen, dass die concat()-Methode StringBuilder verwenden sollte, aber aufgrund der zusätzlichen Erstellung von StringBuilder Die Ausführung der Operation .append(str).append(str).toString() wirkt sich auf die Leistung von Concate aus, also StringBuilder und String Die Cancate-Zeiten betragen 1,8 und 3,3.
Selbst wenn wir die einfachste Verkettung durchführen und keine StringBuffer- oder StringBuilder-Instanz erstellen möchten, sollten wir daher concat verwenden. Für eine große Anzahl von String-Splicing-Vorgängen sollten wir jedoch kein Concat verwenden (Anmerkung des Übersetzers: Da der Testcode in seiner Funktion nicht vollständig gleichwertig ist, beträgt die durchschnittliche Verarbeitungszeit von Concat im ersetzten Testcode 1650,9 Millisekunden. Dieses Ergebnis ist im Originaltextkommentar), da Concat die Leistung Ihres Programms verringert und Ihre CPU verbraucht. Um die höchste Leistung zu erzielen, ohne Thread-Sicherheit und Synchronisierung zu berücksichtigen, sollten wir daher versuchen, StringBuilder zu verwenden.