Java Agent的应用:打印线程池中未捕获异常的日志

本文作者:suxingrui
本文链接:http://www.noobyard.com/article/p-octsntqp-va.html
版权声明:本文为原创文章,转载请注明出处。

程序开发过程中,我们经常会使用线程或线程池进行一些处理。
使用的时候,可能会一个不小心忘记加上try catch或者catch的异常范围不够,而导致出现异常时,未能够捕获到该异常。
表现为线程跑飞,执行到某个点就没了,没了,没了。日志不充足时,问题更是难以调查,尤其是概率出现在生产环境的问题。


线程

可以在启动类中添加
这里写图片描述
以便把未捕获的异常输出到日志。

线程池

线程池中,或者直接执行Runnable任务,或者执行用FutureTask装饰之后的Runnable任务。
执行FutureTask装饰后的任务时出现的未捕获异常不能够通过上述方式进行处理。

如下图所示,FutureTask会捕获该异常,在setException中也没有特别的处理,所以任务抛出异常时,不能把异常输出到日志,也不容易发现问题。
这里写图片描述
这里写图片描述

为了达到我们的目的:打印线程池中未捕获异常的日志

1、要求所有开发人员在添加线程任务时,都要使用try catch(Throwable t),但总有各种各样的原因会遗漏。。。

2、如ThreadPoolExecutor.afterExecute的说明,使用自定义线程池进行处理
这里写图片描述
这里写图片描述
也会有这样那样的原因导致落实不到位。。。

3、分析之后,发现如果能在FutureTask.setException中添加一行代码,就能够完美解决问题。


所以问题就变更为:

如何修改JDK中的类FutureTask

调查之后发现:直接修改JDK源码,不太现实。所以决定使用Javassist修改FutureTask的字节码,同时又因为JVM类的加载机制、双亲委派等原因,需要使用Java Agent。(不了解Javassist、Java Agent的请搜索各路大神的博客、论坛等)

实现:
InstrumentAgent
这里写图片描述
FutureTaskTransformer
这里写图片描述
AgentEventHandler
这里写图片描述

编译,打包,测试:
1、启动添加
这里写图片描述
2、执行测试
这里写图片描述
3、测试结果
这里写图片描述


必要的时候,我们还可以修改其他类,以达到我们的目的。