2010-12-07 2 views
2

In dem Client-Programm, auf dem ich arbeite, versenden wir Serveraufrufe an verschiedene Threads, um die Benutzeroberfläche nicht zu sperren (äquivalent zu einem SwingWorker).Wie kann der ursprüngliche Stack-Trace in einem neu erstellten Thread nachverfolgt werden?

Dies wird mit einem Modellklasse erbt eine abstrakte Klasse, welche die „update“ Verfahren, hergestellt, das den neuen Faden bereitet, und in diesen neu geschaffenen Gewinden (plus anderen Optimierungen)

den Code aus einer abstrakten Methode ausführt

Es funktioniert korrekt, aber mein Problem ist, dass es beim Debugging (oder Logging) schwer ist, den genauen Weg der Methode "update" zu verfolgen, da der Stack-Trace mit der Erstellung des neuen Threads endet.

Was wäre der richtige Weg, um den Stack-Trace zu verfolgen, der dazu führte, dass dieser neue Thread aufgerufen wurde? Idealerweise in einer Weise, die im Stack-Navigator des Debuggers angezeigt wird (in diesem Fall von Eclipse; die Idee besteht darin, einfach im ursprünglichen Kontext zu navigieren).

Antwort

2

Eine gute Möglichkeit, einen StackTrace effizient zu speichern, besteht darin, einfach eine Ausnahme zu konstruieren. Später, wenn Sie den Stacktrace-Aufruf exception.getStackTrace() untersuchen möchten, wird die langsame Arbeit der Auflösung der Stapelrahmen zu Methoden tun.

So können Sie eine new Exception auf die Konstruktion Ihres Worker-Threads erstellen oder an den Arbeitsthread übergeben. Beachten Sie, dass Sie eclipse zum Auswerten von exception.getStackTrace() aufrufen müssen, da das Ausnahmeobjekt zuvor nicht über die Details verfügt.

Übrigens sollten Sie wahrscheinlich einen ExecutorService verwenden, um den Lebenszyklus Ihrer Threads zu verwalten.

bearbeiten Ich schlage diese Weise, weil es eine minimale Auswirkung auf die Leistung im üblichen Fall haben, wo Sie wollen nicht den Stack-Trace zu sehen.

+0

Speichern der Stack-Trace (oder in diesem Fall eine Ausnahme) wäre in der Tat eine Idee. Leider würde es die Information nur in "Variablen" geben, nicht im Stackbaum von Eclipse. Aber ich denke, dass es zu trickreich/hacky wäre, wenn es dort auftauchen würde. – Gnoupi

2

In der Regel werden die Stack-Spuren nicht gekreuzt, so dass es schwierig wird. im Konstruktor Ihrer Worker-Klasse Sie können jedoch den aktuellen Thread Zugriff mit ...

Thread current = Thread.currentThread 

Anschließend können Sie den aktuellen Stack-Trace von diesem Thread bekommen durch den Aufruf ...

StackTraceElement[] currentStack = current.getStackTrace(); 

Sie Anschließend können Sie das in einer Instanzvariablen für Ihren Worker speichern und von Ihrem Debugger aus anzeigen. Dies muss getan werden, bevor das Steuerelement in den neuen Thread übergeht, deshalb schlug ich vor, es im Konstruktor zu machen. Jede Methode, die vor der Methode start() des neuen Threads aufgerufen wird, ist jedoch in Ordnung.

+0

Nahe bei der Lösung, die von daveb gegeben wird, mit dem Unterschied, dass es den tatsächlichen Aufruf zu "getStackTrace" hinzufügen würde, und vielleicht ein bisschen schwerer für die Fälle, wenn ein solches Debuggen nicht erforderlich ist. Vielen Dank für die Details. – Gnoupi

1

Sie sagen, dass Sie "wie SwingWorker" tun. Warum verwenden Sie in diesem Fall keine ExecutorService? Java-Concurrent-Framework ist ziemlich gut gemacht, und würde Ihnen erlauben, die klassischen Fallen des Threading zu vermeiden, darunter Ihre Frage.

+0

Das "Framework" mit diesen Threaded-Calls wurde vor (ohne) Kenntnis des Concurrent-Pakets gemacht, weshalb es in gewisser Weise "von Hand" gemacht wird. Es gibt viel gebaut, also ist es nicht trivial, es zu ändern. Ich bin jedoch daran interessiert zu wissen, was dies verbessern könnte. Würde es mir erlauben zu wissen, welche Methode meine "callable" genannt wird, wenn ich einen Breakpoint in der tatsächlich aufgerufenen Behandlung habe? – Gnoupi

0

Ich hatte gerade das gleiche Problem - mehrere Punkte im System wurden eine Mail durch die gleiche Logik in einem ExecutorService verpackt gesendet.

Genau wie @daveb ich eine leere Exception erstellen und geben es in die Runnable:

Executors.newSingleThreadExecutor().submit(new Mailer(..., new Exception())); 

nun innerhalb von Mailer Ich habe die Exception Instanz in Protokollierung Ausdrücke zu verwenden:

public Mailer(..., final Exception originalStackKeeper) { 
    ... 
    this.originalStackKeeper = originalStackKeeper; 
} 

... 
LOG.error("There was an error while sending mail, originating here: ", 
    originalStackKeeper); 

Aber noch besser: Immer wenn ich eine Ausnahme in Mailer erhalte, kann ich das tun:

} catch (final SomeException e) { 
    LOG.error("There was an error while sending mail.", 
     originalStackKeeper.initCause(e)); 
} 

Also sage ich das Original Exception: Lassen Sie uns Ihren Stack verwenden: Hier ist der Grund, warum wir Sie verwenden, und hier protokollieren wir Sie. Es scheint mir, dass dies nicht wirklich ein Hack ist, sondern eine saubere Methode, den "Ursache" -Mechanismus in Java-Ausnahmen zu verwenden.

Verwandte Themen