在我工作的客户端程序中,我们将服务器调用分派给不同的线程,以便不锁定UI(相当于SwingWorker)。
这是通过继承包含“update”方法的抽象类的模型类来完成的,该方法正在准备新线程,并在这个新创建的Thread中执行抽象方法的代码(加上其他调整)
它工作正常,但我的问题是,在调试(或记录)时,很难跟踪哪个方法完全称为“更新”方法,因为堆栈跟踪以创建新线程结束。 / p>
跟踪导致调用此新线程的堆栈跟踪的正确方法是什么?理想情况下,在调试器的堆栈导航器中显示的方式(在这种情况下来自Eclipse) ;这个想法是在初始背景下轻松导航。)
答案 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异常中使用“原因”机制的简洁方法。