Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在新创建的线程中跟踪原始堆栈跟踪的正确方法是什么?_Java_Multithreading_Stack Trace - Fatal编程技术网

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

Java 在新创建的线程中跟踪原始堆栈跟踪的正确方法是什么?,java,multithreading,stack-trace,Java,Multithreading,Stack Trace,在我工作的客户机程序中,我们将服务器调用分派到不同的线程,以不锁定UI(相当于SwingWorker) 这是通过一个模型类继承一个包含“update”方法的抽象类来实现的,这个抽象类正在准备新线程,并在这个新创建的线程中从一个抽象方法执行代码(加上其他调整) 它工作正常,但我的问题是,在调试(或记录)时,很难跟踪哪个方法确切地称为“update”方法,因为堆栈跟踪以创建新线程结束 跟踪导致调用此新线程的堆栈跟踪的正确方法是什么?理想情况下,以调试器的堆栈导航器中显示的方式(在本例中来自Eclip

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

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

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


跟踪导致调用此新线程的堆栈跟踪的正确方法是什么?理想情况下,以调试器的堆栈导航器中显示的方式(在本例中来自Eclipse;目的是在初始上下文中轻松导航).

有效存储stacktrace的一个好方法是简单地构造一个异常。稍后,如果要检查stacktrace调用
exception.getStackTrace()
,它将执行将堆栈帧解析为方法的缓慢工作

因此,您可以在构建工作线程时创建一个
新异常
,或者将其传递给工作线程。注意,您必须让eclipse计算exception.getStackTrace(),因为在您计算exception.getStackTrace()之前,exception对象不会有详细信息

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);
    }
}
公共抽象类工作程序{
受保护的抽象对象doTheWork();
公共未来更新(){
异常堆栈=新异常();
可调用作业=新的可调用内容(堆栈);
返回提交作业(作业);
}
}
顺便说一句,您可能应该使用ExecutorService来管理线程的生命周期

编辑
我之所以建议这样做,是因为在通常情况下,如果您不想看到堆栈跟踪,它对性能的影响最小。

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

Thread current = Thread.currentThread
然后,您可以通过调用

StackTraceElement[] currentStack = current.getStackTrace();

然后,您可以将其存储在worker的实例变量中,并从调试器中查看。这必须在控件传递到新线程之前完成,这就是为什么我建议在构造函数中执行它。但是,在新线程的
start()
方法之前调用的任何方法都可以。

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

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

就像@daveb一样,我创建了一个空的
异常
,并将其传递到
可运行的

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));
}

所以我告诉原始的
异常
:让我们使用你的堆栈:这是我们使用你的原因,这里我们记录你。在我看来,这并不是真正的黑客行为,而是一种在Java异常中使用“原因”机制的干净方法。

带有这些线程调用的“框架”是在不知道并发包之前(不知道)完成的,所以这就是为什么它是以某种方式“手工”完成的。周围有很多东西,所以改变它不是一件小事。然而,我很想知道这能改善什么。如果我在实际调用的处理中有一个断点,它能让我知道哪个方法称为我的“callable”吗?存储堆栈跟踪(或者在本例中是一个异常)确实是一个好主意。不幸的是,它只在“变量”中提供信息,而不是在Eclipse的堆栈树中。但我想,让它出现在那里太棘手了。与daveb给出的解决方案很接近,不同的是它会添加对“getStackTrace”的实际调用,对于不需要这种调试的情况,可能会稍微重一点。不过,谢谢你提供的细节。