我正在考虑的情况是在一个多读应用程序中使用它。假设我的主线程(我们将其称为Prime)需要启动另一个线程(我们将其称为Daemon)来在后台执行某些操作。
守护程序线程可以从Prime线程中的几个不同位置启动,如果守护程序线程遇到错误,我想知道Prime线程中最初启动守护程序线程的哪段代码失败了。
因此,假设我在Prime线程中创建了一个new Exception("some message"),将其传递给守护线程(例如,在其构造函数中),然后启动守护线程。
如果守护进程执行时没有错误,则永远不会使用异常,并且我希望避免支付跟踪堆栈的成本。
另一方面,如果守护进程有异常发生,我希望它能够使用来自Prime线程的异常以及守护进程自己的异常来帮助调试。来自Prime线程异常的堆栈跟踪将指示守护进程产生的位置,而来自守护进程的堆栈跟踪将指示在守护进程中遇到问题的位置。
如果我这样做,我是否必须为每种情况支付Prime线程的异常的处理成本,或者只是在Daemon线程遇到错误并随后查看Prime线程的异常堆栈的情况下?
发布于 2016-08-05 05:46:21
异常的堆栈跟踪是在构造异常时填充的。如果您查看java.lang.Throwable的构造函数,它们看起来都像something like
public Throwable() {
fillInStackTrace();
}
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;
}其中fillInStackTrace()是构建堆栈跟踪的方法。所以,是的,你必须支付堆栈跟踪构造的成本,无论它是否被抛出。
然而,我预计构造线程的成本会高得多。
发布于 2016-08-05 06:42:57
据我所知,您希望在创建新线程的地方保留堆栈跟踪的某些部分,以便进一步调试。
当然,您可以只调用new Exception().getStackTrace(),但它可能是您的瓶颈,因为遍历所有堆栈并不便宜。如果您使用的是HotSpot,则可以使用私有StackTraceElement访问一个API,这是最常见的情况,通常足以满足调试/日志记录的需要。sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement()就是该应用程序接口,但在JDK9中将不可用。在JDK9中,您将能够使用Stack-Walking API。
这是一个基准测试
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class StackTraces {
@Benchmark
public StackTraceElement[] getStackTrace() {
return new Exception().getStackTrace();
}
@Benchmark
public StackTraceElement getFast() {
return sun.misc.SharedSecrets.getJavaLangAccess()
.getStackTraceElement(new Exception(), 2);
}
}结果是:
Benchmark Mode Cnt Score Error Units
StackTraces.getFast avgt 5 2.799 ± 0.066 us/op
StackTraces.getStackTrace avgt 5 14.014 ± 0.290 us/op附注:你可以通过重写fillInStackTrace来创建没有任何堆栈跟踪的异常(非常便宜)。此外,如果您在快速路径上抛出异常,HotSpot可以对其进行缓存,并省去创建堆栈跟踪。可以使用选项-XX:-OmitStackTraceInFastThrow禁用此行为
new Exception() {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}https://stackoverflow.com/questions/38776308
复制相似问题