2016-03-24 7 views
0

Ich wurde mit diesem Code drucken den Benutzer, wenn REST-Schnittstellen verfügbar worden benachrichtigen:Wie die gleiche Linie von Multi-Threaded-Anwendung

Console.printTermNoBreak("Waiting for interface on host [" + localTarget.getHostName() + "]"); 

Wenn die Schnittstelle nach oben kam, dann würde es drucken ‚OK 'mit einem Zeitstempel, wie lange es dauerte zu kommen:

Console.SYS_LOGGER.info("[OK]" + " (" + (endTime - startTime + "ms") + ")"); 

auf der Konsole, die wie folgt aussehen:

Waiting for interface on host [dubengvm272]   [OK] (413ms) 

Also beide Appender schreiben in dieselbe Zeile. Ich habe den Code so überarbeitet, dass mehrere Threads unterschiedliche Schnittstellen auf verschiedenen Rechnern aufrufen.

Jetzt, da alle Threads zu unterschiedlichen Zeiten fertig sind, ist die Konsole verstümmelt. Ich frage mich nur, ob ich auf die gleiche Weise wie vorher ausdrucken kann, auch wenn es nicht genau wiedergibt, was im Hintergrund passiert.

+0

Muss die Ausgabe auf der Konsole live sein? Kann es gepuffert und später ausgegeben werden? – weston

Antwort

1

Wenn Sie die Atomarität Zeile für Zeile möchten, müssen Sie Ihre Zeile auf einmal schreiben. Wenn Ihre Linie aus mehreren Teilen besteht, müssen Sie diese Teile zuerst zu einer einzigen Linie zusammenfassen und dann diese Linie ausschreiben, wenn sie fertig ist.

Aber es gibt zusätzliche Probleme, auch wenn einzelne Threads komplette Zeilen auf einmal schreiben, können Sie immer noch mit sich überlappenden Zeilen enden. Dies kann zum Beispiel bei gepufferten IOs passieren, bei denen der gepufferte Writer nicht Thread-sicher ist oder wenn die Zeile groß genug ist, um die Puffergröße zu überschreiten, und daher intern aufgeteilt und in mehreren Schritten geschrieben werden muss.

Zumindest beim Linux-Schreiben in Dateien/Pipes, die mit O_APPEND geöffnet werden, bietet Ihnen eine gewisse Atomizität, aber das ist plattformspezifisch, kommt mit einigen Vorbehalten und löst das Pufferungsproblem nicht.

Eine allgemeinere Lösung für die Protokollierung besteht darin, Ihre Protokollelemente als Ganzes in eine thread-sichere Warteschlange zu pushen und eine Thread-Abfrage aus der Warteschlange zu erstellen und auf Ihre Ausgabe Element für Element zu schreiben. Auf diese Weise können Sie auch mehrere Werbebuchungen verwenden.

Mit einem separaten Logger-Thread wird auch die Leistung verbessert, da die Protokollierung IO ist und unnötige Latenz auf Ihrem Haupt-Codepath verursachen kann. Auf diese Weise wird der Logger-Thread ein "Opfer-Thread" für die IO-Strafe.

LinkedTransferQueue ist ein guter Kandidat für die Warteschlange, da die Übergabe an die Warteschlange nicht durch eine gemeinsame Sperre blockiert wird. Ein potenzieller Nachteil besteht darin, dass es unbegrenzt ist und potenziell OOMs in Situationen verursachen kann, in denen der Logger-Thread nicht mit den Protokollübermittlern mithalten kann. Aber wenn das passiert, hast du wahrscheinlich sowieso ein Problem.

Wenn Ihr Logger bereits Thread-sicher ist, müssen Sie Ihre Ausgabe einfach in einer einzigen Zeile ausschreiben, anstatt zwei separate Protokollaufrufe.

Verwandte Themen