从Dubbo的线程池拒绝策略到线程泄露分析

       开篇讲一下,为什么要写线程池饱和后的拒绝策略。早在上个月,就要说写一篇除 java.util.concurrent包之外的四种线程池拒绝策略,开源框架如:ActiveMQ,Dubbo,PinPoint,Netty也都实现了符合自己业务的拒绝策略。

然而一直没有动手,直到今天手残的点开一篇博客如下:

本打算快速浏览一遍,竟然看到不敢相信的几行代码,代码如下:

       首先,这是业务操作是:在执行了自定义的拒绝策略后,调用方法dumpJStack() 用输出流的方式输出线程信息到某个路径的文件。那么问题来了,这种在方法内部创建的线程池会不会有线程泄露的风险?这种行编码方式也决定了接下来的代码不可能有shutdown()这样的操作。

-------------------------------------------- 格叽格叽格叽格叽格叽格叽 一休哥来啦----------------------------------------------

那我们自己来实验一下到底有没有问题吧!

       可以确定的是局部创建的线程池是不会在方法执行完毕后回收,具体为什么局部线程池没有被回收,不在本文讨论的重点,请自行百度一下。这里只用简单的代码测试一下这个结论。


测试代码如下:

先来看反例代码及线程监控:

执行一次后的线程视图和dump下的信息:

       经过分析上图,发现局部线程池在线程任务执行完毕后线程没有被回收,而是wating的状态驻留,从而导致线程泄露(因为不可能再使用到这个线程池)。

反例分析过后,修改下测试代码,再次对比,如何回收局部线程池

正例代码测试:

修改的代码中打开了shutdown的注释。

观察几张图,可以确定的是线程被回收了,从而避免了线程泄露。

       现在可以真正的确定如果没有手动调用shutdown,局部的线程池创建会存在线程泄露的风险,那么Duboo中是否真的像开篇的文章一样,没有回收线程呢?

       本着对阿里的敬意,从最大的同性交友网站GitHub上down下源码,下面是贴源码时间。

首先找到了线程池相关的类

Dubbo中实现了自己的线程池,但本质上还是ThreadPoolExecutor。

经查看几种线程池的饱和策略都是一个叫作

AbortPolicyWithReport的策略类。

找到了正主,发现是继承了并发包下的一个直接抛异常的拒绝策略

重写了rejectedExecution方法

但是发现和本文开始的代码贴图不太一样。对,就是你想的那样,这里的局部线程池被回收了,脚趾头想一下也不相信会有这么低级的错误,而且注释很有意思。

那么为什么开篇文章的贴图中会没有回收的代码,本着开源精神,查看一下git log,果然如此。

在19年1月份已经被修复了。

下面我们再来看一下,Dubbo的拒绝策略到底做了什么。

首先输出warn级别的线程池信息日志,打印的日志真是标准的典范。

然后dump下线程相关信息,就是这样。

Dubbo的线程池拒绝策略就是上述内容,没有什么难度,但是很标准的记录了饱和当时的线程信息,方便排查。

接下来会分享其他开源框架中关于线程池拒绝策略的分析,感谢呦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章