Java: System.aus.println und System.err.println, out of order
Meine System.out.println()
und System.err.println()
Anrufe werden nicht auf der Konsole ausgegeben in der Reihenfolge in der ich Sie machen.
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
System.out.println("out");
System.err.println("err");
}
}
Diese produziert:
out
out
out
out
out
err
err
err
err
err
Statt abwechselnd out
und err
. Warum ist das so?
InformationsquelleAutor Nick Heiner | 2009-12-10
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie verschiedenen streams und geleert werden, zu unterschiedlichen Zeiten.
Wenn Sie
innerhalb der Schleife, wird es funktionieren wie erwartet.
Klären, output-streams werden zwischengespeichert, so dass alle das schreiben geht in dieser Speicher-Puffer. Nach einer Zeit der Ruhe, Sie sind tatsächlich geschrieben.
Schreiben Sie zwei Puffer, dann nach einem Zeitraum der Inaktivität, die Sie beide sind geleert (eins nach dem anderen).
Bereits eine Antwort auf Stack Overflow Thema Java: die Synchronisierung von standard-out und standard-error
Diese Antwort ist tatsächlich falsch, da
System.out
undSystem.err
sollte automatisch geleert, bei jedem Zeilenumbruch, der ist eindeutig vorhanden, wie die Anrufe verwenden dieprintln()
. Also das sollte nicht den Unterschied machen.Sie benutzen das Wort viel... haben Sie tatsächlich versucht?
Antwort ist falsch. Diese Ströme autoflush.
InformationsquelleAutor Bill K
Verursacht wird dies durch eine Funktion in der JVM und es sei denn, Sie machen ein hack wie das von Marcus A. es ist nicht wirklich leicht zu umgehen. Die
.flush()
funktioniert in diesem Fall aber der Grund für dies ist viel komplizierter zu umgehen.Was ist hier passiert?
Wenn Sie das Programm in Java bist du nicht sagen, den computer direkt, was zu tun ist, du erzählst die JVM (Java Virtual Machine), was würden Sie wollen, es zu tun. Und es wird das tun, aber in einer effizienteren Art und Weise. Ihr code nicht genaue detaillierte Anweisungen, in diesem Fall würden Sie brauchen nur einen compiler wie bei C und C++, die JVM nimmt Ihren code als Spezifikations-Liste für das, was es soll, zu optimieren und dann tun. Dies ist, was passiert hier. Java sieht, dass Sie schieben Saiten in zwei verschiedene buffer-streams. Der effizienteste Weg dies zu tun ist durch die Pufferung werden alle Zeichenfolgen, die Sie wollen, dass die streams ausgeben und dann die Ausgabe. Diese passieren einen stream an der Zeit, die im wesentlichen verwandelt Ihren code so etwas tun (Achtung: pseudo-code):
Weil dies effizienter ist, dies ist, was die JVM wird stattdessen tun. Hinzufügen der
.flush()
in der loop-signal an die JVM, dass ein flush muss getan werden, in jeder Schleife, die verbessert werden kann nicht mit der oben beschriebenen Methode. Aber wenn du für den Willen zu erklären, wie das funktioniert hätte verlassen Sie die Schleife, die JVM ordnet Ihren code zu haben, der Druck dauern, da dies effizienter ist.Dieser code wird immer wieder neu organisiert, so etwas wie dieses:
Weil die Pufferung viele Puffer nur Spülen Sie Sie gleich nach der braucht viel mehr Zeit als Puffer den code gepuffert werden, und dann Spülen Sie es alle zur gleichen Zeit.
, Wie es zu lösen
Dies ist, wo code-design und-Architektur könnte ins Spiel kommen; Sie irgendwie nicht lösen. Um dies zu umgehen, müssen Sie noch effizienter werden, um Puffer drucken/flush, Puffer drucken/flush als Puffer, dann Spülen. Dies wird wahrscheinlich sein, locken Sie in bad-design. Wenn es Ihnen wichtig ist, wie die Ausgabe ihn ordentlich, ich schlage vor, Sie versuchen einen anderen Ansatz. For-Schleife mit
.flush()
ist eine Möglichkeit, es zu hacken, aber du bist immer noch das hacken der JVM-Funktion zum re-arrangieren und optimieren Sie Ihren code für Sie.*
Ich kann nicht stellen Sie sicher, dass die Puffer, die Sie Hinzugefügt, um erste wird immer zuerst gedruckt, aber es wahrscheinlich wird.InformationsquelleAutor Gemtastic
Wenn Sie mit der Eclipse-Konsole, scheint es zwei unterschiedliche Phänomene bei der Arbeit:
Ein, wie oben beschrieben, durch @Gemtastic, ist die JVMs Umgang mit den Bächen und der andere ist der Weg der Eclipse liest diese Ströme, wie bereits erwähnt, durch @DraganBozanovic. Da bin ich mit Eclipse, eleganten
flush()
-Lösung geschrieben von @BillK, die nur Adressen der JVM-Problem, ist nicht ausreichend.Landete ich schreiben mir eine helper-Klasse namens
EclipseTools
mit folgendem Inhalt (und die erforderlichen Paket-Deklaration und-Importe). Es ist ein bisschen ein hack, aber behebt beide Probleme:Verwenden, rufen Sie einfach
EclipseTools.fixConsole()
einmal in den Anfang des Codes.Grundsätzlich ersetzt die beiden streams
System.err
undSystem.out
mit einen benutzerdefinierten Satz von Datenströmen, schicken Sie einfach Ihre Daten in die original-streams, aber behalten, welche Bach geschrieben wurde zuletzt. Wenn der stream geschrieben wird, auf Veränderungen, zum Beispiel eineSystem.err.something(...)
gefolgt von einemSystem.out.something(...)
, es spült den Ausgang der letzten Strom-und wartet 200ms zu geben, die Eclipse-Konsole Zeit, um zu drucken.Hinweis: Die 200 MS sind nur ein grober Startwert. Wenn dieser code reduziert, aber nicht beseitigt, das problem für Sie ist, erhöhen Sie die Verzögerung in
Thread.sleep
von 200 bis etwas höher, bis es funktioniert. Alternativ, wenn diese Verzögerung funktioniert, aber schlägt in der performance des Codes (wenn Sie Alternative Datenströme oft), Sie können versuchen, reduzieren Sie allmählich, bis Sie anfangen, Fehler.InformationsquelleAutor Markus A.
Den beiden
println
- Anweisungen verarbeitet werden, die von zwei verschiedenen threads. Der Ausgang wieder hängt davon ab, in welcher Umgebung Sie sind der code ausgeführt wird.Für zB, habe ich ausgeführt, den folgenden code in IntelliJ-und Befehls-Zeile 5-mal an.
Dies resultiert in folgender Ausgabe:
Commandline
IntelliJ:
Ich denke, verschiedene Umgebungen behandelt die Puffer unterschiedlich.
Ein Weg, um zu sehen, dass diese Ströme sind in der Tat behandelt, die von verschiedenen threads ist das hinzufügen einer
sleep
Anweisung in der Schleife. Sie können versuchen, die Variation der Wert, den Sie für die schlafen und sehen, dass diese infact behandelt, die von verschiedenen threads.Die Ausgabe in diesem Fall stellte sich heraus, dass
Einer Weise zu zwingen, es zu drucken, in der gleichen Reihenfolge sein würde, verwenden Sie die
.flush()
, die für mich gearbeitet hat. Aber itseems, dass nicht jeder immer die richtigen Ergebnisse.Die beiden Ströme behandelt, die durch 2 andere threads ist wohl auch der Grund, warum wir manchmal das
ERROR
Nachricht gedruckt durch einige Bibliotheken, die wir verwenden, wird immer gedruckt, bevor einige print-Anweisungen, dass wir sehen sollen entsprechend der Reihenfolge der Ausführung.InformationsquelleAutor Some guy
Dies ist ein Fehler in Eclipse. Es scheint, dass Eclipse verwendet separate threads zu Lesen, den Inhalt
out
underr
streams ohne Synchronisierung.Wenn Sie kompilieren Sie die Klasse und führen Sie es in der Konsole (mit den klassischen
java <main class name>
), ist die Reihenfolge wie erwartet.InformationsquelleAutor Dragan Bozanovic
Habe ich benutzt, den thread zu drucken, die Ausgabe von System.out und System.err nacheinander:
InformationsquelleAutor Milan Paudyal