在新创建的线程中跟踪原始堆栈跟踪的正确方法是什么?

发布于 2024-10-06 14:18:41 字数 315 浏览 2 评论 0原文

在我工作的客户端程序中,我们将服务器调用分派到不同的线程,以免锁定 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一片旧的回忆 2024-10-13 14:18:41

通常,堆栈跟踪不会跨线程,因此这将很棘手。但是,在 Worker 类的构造函数中,您可以通过以下方式访问当前线程...

Thread current = Thread.currentThread

然后您可以通过调用...来获取该线程的当前堆栈跟踪...

StackTraceElement[] currentStack = current.getStackTrace();

然后您可以将其存储在您的工作线程的实例变量中并查看从你的调试器。这必须在控制传递到新线程之前完成,这就是为什么我建议在构造函数中执行此操作。但是,在新线程的 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...

Thread current = Thread.currentThread

You can then get the current stack trace of that thread by calling...

StackTraceElement[] currentStack = current.getStackTrace();

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.

安人多梦 2024-10-13 14:18:41

有效存储堆栈跟踪的一个好方法是简单地构造一个异常。稍后,如果您想检查堆栈跟踪,请调用 exception.getStackTrace() ,这将完成将堆栈帧解析为方法的缓慢工作。

因此,您可以在工作线程的构造中创建一个new Exception,或者将其传递给工作线程。请注意,您必须让 Eclipse 来评估Exception.getStackTrace(),因为在您执行之前异常对象不会有详细信息。

public abstract class Worker {
    protected abstract Object doTheWork();
    public Future<Object> update() {
        Exception stack = new Exception();
        Callable<Object> job = new WhateverYourCallableIs(stack);

        return submitJob(job);
    }
}

顺便说一句,您可能应该使用 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.

public abstract class Worker {
    protected abstract Object doTheWork();
    public Future<Object> update() {
        Exception stack = new Exception();
        Callable<Object> job = new WhateverYourCallableIs(stack);

        return submitJob(job);
    }
}

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.

挽梦忆笙歌 2024-10-13 14:18:41

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.

锦欢 2024-10-13 14:18:41

我刚刚遇到了同样的问题 - 系统中的多个点通过封装在 ExecutorService 中的相同逻辑发送邮件。

就像@daveb一样,我创建了一个空的Exception并将其传递到Runnable中:

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

现在在Mailer内部我有Exception 实例在日志表达式中使用:

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

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

但更好的是:每当我在 Mailer 中捕获异常时,我可以这样做:

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

所以我告诉原来的 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 the Runnable:

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

Now inside of Mailer I have the Exception instance to use in logging expressions:

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

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

But even better: whenever I catch an exception in Mailer, I can do this:

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文