关于消除异常的性能消耗,他提出了三个解决方案:
重构你的代码不使用它们。
缓存异常实例。
重写 fillInStackTrace 方法。
通过小日...小日子过的还不错的日本的站点,输入关键信息后,知乎的这个链接排在第二个:
https://www.zhihu.com/question/21405047
这个问题下面,有一个R大的回答,粘贴给你看看:
大家都不约而同的提到了重写 fillInStackTrace 方法,这个性能优化小技巧,也就是我们可以这样去自定义异常:
用一个不严谨的方式测试一下,你就看这个意思就行:
重写了 fillInStackTrace 方法,直接返回 this 的对象,比调用了爬栈方法的原始方法,快了不是一星半点儿。
其实除了重写 fillInStackTrace 方法之外,JDK 7 之后还提供了这样的一个方法:
java.lang.Throwable#Throwable(java.lang.String, java.lang.Throwable, boolean, boolean)
可以通过 writableStackTrace 入参来控制是否需要去爬栈。
那么到底什么时候才应该去用这样的一个性能优化手段呢?
其实R大的回答里面说的很清楚了:
其实我们写业务代码的,异常信息打印还是非常有必要的。
但是对于一些追求性能的框架,就可以利用这个优势。
比如我在 disruptor 和 kafka 的源码里面都找到了这样的优化落地源码。
先看 disruptor 的:
com.lmax.disruptor.AlertException
- Overridden so the stack trace is not filled in for this exception for performance reasons.
- 由于性能的原因,重载后的堆栈跟踪不会被填入这个异常。
再看 kafka 的:
org.apache.kafka.common.errors.ApiException
- avoid the expensive and useless stack trace for api exceptions
- 避免对api异常进行昂贵而无用的堆栈跟踪
而且你注意到了吗,上面着两个框架中,直接把 synchronized 都干掉了。如果你也打算重写,那么也可以分析一下你的场景中是否可以去掉 synchronized,性能又可以来一点提升。
另外,R大的回答里面还提到了这个优化是 C2 的优化。
我们可以简单的证明一下。