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

时间:2010-12-07 14:07:42

标签: java multithreading stack-trace

在我工作的客户端程序中,我们将服务器调用分派给不同的线程,以便不锁定UI(相当于SwingWorker)。

这是通过继承包含“update”方法的抽象类的模型类来完成的,该方法正在准备新线程,并在这个新创建的Thread中执行抽象方法的代码(加上其他调整)

它工作正常,但我的问题是,在调试(或记录)时,很难跟踪哪个方法完全称为“更新”方法,因为堆栈跟踪以创建新线程结束。 / p>

跟踪导致调用此新线程的堆栈跟踪的正确方法是什么?理想情况下,在调试器的堆栈导航器中显示的方式(在这种情况下来自Eclipse) ;这个想法是在初始背景下轻松导航。)

4 个答案:

答案 0 :(得分:2)

有效存储堆栈跟踪的一种好方法是简单地构造一个异常。稍后,如果你想检查一下堆栈跟踪调用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来管理线程的生命周期。

修改 我建议这样做,因为在你不想看到堆栈跟踪的通常情况下,它对性能的影响很小。

答案 1 :(得分:2)

通常堆栈跟踪不会跨越线程,因此这将非常棘手。但是,在Worker类的构造函数中,您可以使用...

访问当前线程
Thread current = Thread.currentThread

然后,您可以通过调用...

来获取该线程的当前堆栈跟踪
StackTraceElement[] currentStack = current.getStackTrace();

然后,您可以将其存储在工作人员的实例变量中,并从调试器中查看该变量。这必须在控件进入新线程之前完成,这就是我建议在构造函数中执行此操作的原因。但是,在新线程的start()方法之前调用的任何方法都可以。

答案 2 :(得分:1)

你说你“喜欢SwingWorker”。在这种情况下,为什么不使用ExecutorService? Java并发框架做得很好,可以让你避免线程的经典陷阱,其中包括你的问题。

答案 3 :(得分:0)

我遇到了同样的问题 - 系统中的多个点通过包含在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:让我们使用你的堆栈:这就是我们使用你的原因,在这里我们正在记录你。在我看来,这不是一个真正的黑客,而是一种在Java异常中使用“原因”机制的简洁方法。