在新创建的线程中跟踪原始堆栈跟踪的正确方法是什么?
在我工作的客户端程序中,我们将服务器调用分派到不同的线程,以免锁定 UI(相当于 SwingWorker)。
这是由继承包含“更新”方法的抽象类的模型类制成的,该方法正在准备新线程,并从这个新创建的线程中的抽象方法执行代码(加上其他调整)
它工作正常,但我的问题问题在于,在调试(或记录)时,很难跟踪哪个方法准确地调用了“更新”方法,因为堆栈跟踪以新线程的创建结束。
跟踪导致调用此新线程的堆栈跟踪的正确方法是什么? 理想情况下,以在调试器的堆栈导航器中显示的方式(在本例中来自 Eclipse;想法是为了在初始上下文中轻松导航)。
In the client program on which I work, we dispatch server calls to different Threads, to not lock the UI (equivalent of a SwingWorker).
This is made with a model class inheriting an abstract class containing the "update" method, which is preparing the new thread, and executing the code from an abstract method in this newly created Thread (plus other tweaks)
It works correctly, but my issue is that when debugging (or logging), it is hard to keep track of which method exactly called the "update" method, since the stack trace ends with the creation of the new Thread.
What would be the proper way to keep track of the stack trace which led to call this new Thread? Ideally, in a way which would show in the debugger's stack navigator (from Eclipse in this case; the idea is to navigate easily in the initial context).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
通常,堆栈跟踪不会跨线程,因此这将很棘手。但是,在 Worker 类的构造函数中,您可以通过以下方式访问当前线程...
然后您可以通过调用...来获取该线程的当前堆栈跟踪...
然后您可以将其存储在您的工作线程的实例变量中并查看从你的调试器。这必须在控制传递到新线程之前完成,这就是为什么我建议在构造函数中执行此操作。但是,在新线程的
start()
方法之前调用的任何方法都可以。Typically stack traces don't cross threads so this is going to be tricky. However, in the constructor of your Worker class you could access the current thread with...
You can then get the current stack trace of that thread by calling...
You can then store that in an instance variable for your worker and view that from your debugger. This has to be done before the control passes into the new thread, that's why I suggested doing it in the constructor. However, any method that gets called before the
start()
method of the new thread will be fine.有效存储堆栈跟踪的一个好方法是简单地构造一个异常。稍后,如果您想检查堆栈跟踪,请调用
exception.getStackTrace()
,这将完成将堆栈帧解析为方法的缓慢工作。因此,您可以在工作线程的构造中创建一个
new Exception
,或者将其传递给工作线程。请注意,您必须让 Eclipse 来评估Exception.getStackTrace(),因为在您执行之前异常对象不会有详细信息。顺便说一句,您可能应该使用 ExecutorService 来管理线程的生命周期。
编辑
我建议采用这种方式,因为在您不想看到堆栈跟踪的通常情况下,它对性能的影响最小。
A good way to store a stacktrace away efficiently is to simply construct an exception. Later, if you want to inspect the stacktrace call
exception.getStackTrace()
which will do the slow work of resolving the stack frames to methods.So, you could create a
new Exception
on the construction of your worker thread, or pass it to the worker thread. Note, you'll have to get eclipse to evaluate exception.getStackTrace(), because the exception object won't have the details before you do.Incidentally, you should probably use an ExecutorService to manage the lifecycle of your threads.
Edit
I'm suggesting this way because it will have a minimal impact on performance in the usual case where you don't want to see the stack trace.
你说你“喜欢 SwingWorker”。在这种情况下,为什么不使用 ExecutorService? Java并发框架制作得非常好,可以让您避免线程的经典陷阱,其中包括您的问题。
You say you do "like SwingWorker". In this case, why not using an ExecutorService ? Java concurrent framework is pretty well made, and would allow you to avoid the classic pitfalls of threading, amongst them your question.
我刚刚遇到了同样的问题 - 系统中的多个点通过封装在 ExecutorService 中的相同逻辑发送邮件。
就像@daveb一样,我创建了一个空的
Exception
并将其传递到Runnable
中:现在在
Mailer
内部我有Exception 实例在日志表达式中使用:
但更好的是:每当我在
Mailer
中捕获异常时,我可以这样做:所以我告诉原来的
Exception
:让我们使用你的stack:这就是我们使用你的原因,我们在这里记录你。在我看来,这并不是真正的 hack,而是一种在 Java 异常中使用“原因”机制的干净方法。I just had the same problem - multiple points in the system were sending a mail through the same logic wrapped in an
ExecutorService
.Just like @daveb I create an empty
Exception
and pass it into theRunnable
:Now inside of
Mailer
I have theException
instance to use in logging expressions:But even better: whenever I catch an exception in
Mailer
, I can do this:So I tell the original
Exception
: let's use your stack: here is the cause why we are using you, and here we are logging you. It seems to me that this is not really a hack, but rather a clean way to use the "cause" mechanism in Java exceptions.