我正在使用ExecutorService异步发送邮件,所以有一个类:

class Mailer implements Runnable { ...

处理发送。对于(匿名)示例,记录捕获的任何异常:
javax.mail.internet.AddressException: foo is bar
    at javax.mail.internet.InternetAddress.checkAddress(InternetAddress.java:1213) ~[mail.jar:1.4.5]
    at javax.mail.internet.InternetAddress.parse(InternetAddress.java:1091) ~[mail.jar:1.4.5]
    at javax.mail.internet.InternetAddress.parse(InternetAddress.java:633) ~[mail.jar:1.4.5]
    at javax.mail.internet.InternetAddress.parse(InternetAddress.java:610) ~[mail.jar:1.4.5]
    at mycompany.Mailer.sendMail(Mailer.java:107) [Mailer.class:?]
    at mycompany.Mailer.run(Mailer.java:88) [Mailer.class:?]
    ... suppressed 5 lines
    at java.lang.Thread.run(Thread.java:680) [?:1.6.0_35]

不是很有帮助-我需要查看引起所有这些的ExecutorService调用的stacktrace。我的解决方案是创建一个空的Exception并将其传递到Mailer:
executorService.submit(new Mailer(foo, bar, new Exception()));
...
// constructor
public Mailer(foo, bar, Exception cause) { this.cause = cause; ...

现在,在发生异常的情况下,我想从另一个线程记录问题本身及其原因:
try {
  // send the mail...
} catch (Throwable t) {
  LOG.error("Stuff went wrong", t);
  LOG.error("This guy invoked us", cause);
}

这很好用,但是会产生两个日志。我想将tcause合并为一个异常并记录该异常。我认为t会导致cause,因此使用cause.initCause(t)应该是正确的方法。和工程。我看到了完整的堆栈跟踪:从调用始发地一直到AddressException

问题是,initCause()仅工作一次,然后崩溃。 问题1:我可以克隆Exception吗?我会克隆cause并每次使用t对其进行初始化。

我尝试了t.initCause(cause),但是立即崩溃了。

问题2:是否有另一种巧妙的方式来组合这两个异常?还是仅将一个线程上下文保留在另一个线程上下文中以进行记录?

最佳答案

根据我的评论,这实际上是我的想法。提醒您,我目前无法进行测试。

您从父线程传递的是New Exception().getStackTrace()。或者更好,正如@Radiodef所说的Thread.currentThread().getStackTrace()。因此,它基本上是一个StackTraceElement[]数组。

现在,您可以拥有以下内容:

public class CrossThreadException extends Exception {

    public CrossThreadException( Throwable cause, StackTraceElement[] originalStackTrace ) {

        // No message, given cause, no supression, stack trace writable
        super( null, cause, false, true );

        setStackTrace( originalStackTrace );
    }
}

现在,在您的catch子句中,您可以执行以下操作:
catch ( Throwable cause ) {
   LOG( "This happened", new CrossThreadException( cause, originalStackTrace ) );
}

这将为您提供两个堆栈跟踪之间的边界。

10-04 13:13