Tomcat工作线程池对jdk线程池的改进(线程池之二)

前面其实我们已经对Tomcat的工作线程池进行简单介绍了,其主要是对java.util.concurrent.ThreadExecutor的包装;


本文更加深入的看看包装的一些细节和过程;

Tomcat中Executor组件的一些配置,主要传入StandardThreadExecutor中,然后在该类中对该线程池进行初始化,有如下的代码:


Tomcat对java.util.concurrent.ThreadExecutor包装主要有几点改进:


1.配置ThreadLocalLeakPreventionListener ,该监听器主要监听Server,Context的启停,当Server,Context停止的时候,发出stoping的事件,重新整理工作线程池中的idle线程


这段代码,我们前面介绍ThreadLocalLeakPreventionListener  的时候,多次提到过,setCorePoolSize用法很精妙;

需要注意这段代码中的属性,lastContextStoppedTime代表上一次整理线程的时间戳;


2.自定义TaskThreadFactory,其作用就是个性化定义Thread的名称,这个其实是需要做的,属于线程池需要对线程创建进行个性化:

 

namePrefix:是给线程前面加的前缀名

daemon:该线程是否为daemon线程,默认就是

threadPriority:线程的优先级

上述的三个属性都是从ThreadExecutor的配置中读取的


3.自定义了TaskQueue,这个TaskQueue依然是BlockingQueue,有几个改进比较不错,

首先我们来看看乐观offer,其意思就是对使用线程很乐观:


什么意思,看看下图:


当我们随着工作任务的加多,目前的工作线程的coreSize已经满了,这个时候workqueue的offer方法才被调用,也就是如上的图;

这是正常的逻辑;


但,TaskQueue之所以说其比较乐观,是看到如果当前的coreSize还没有到maxiumSize的最大值,乐观的认为当前线程池还会扩容, 这个时候不想往队列里面加元素了,而是直接offer返回false,直接更大限度的利用线程池中的线程去执行,因为这个时候可能当前的coreSize已经扩容了,也就能执行该任务了,这就是所谓的“乐观”的做法;


对应的代码很简单,就是重写offer方法,只有coresize<maxiumSize的时候,才有潜力可挖,会乐观的使用线程池去执行,其它情况还是super.offer:


这种乐观的做法的好处就是一个形象的比喻就是,会很“凶”的压榨线程池的能力;

对于TaskQueue的第二个改进,就是在poll的时候,


原来的poll是出队列去执行任务,这是很正常的逻辑;

但我们注意到了,因为我们前面讲过,配置了ThreadLocalLeakPreventionListener  ,可以监听应用的停止信息,

我们试想一下,假如任务在workqueue中的过程,应用停止了,这个时候再去执行已经没有意义了,应该中断该任务:


看看代码,实际就是在poll方法中进行了一下判断:


怎么计算这个应用是不是已经stop了呢,这就用到了前面提到的lastContextStoppedTime了,这个也就是currenytThreadShouldBeStopped方法的内容;


4.最后,Tomcat的自定义ThreadExecutor还能看到已经提交了的任务给线程池的总数,也就是submittedCount:


这个是什么意思呢?


如上图所示,从队列卸载下来的任务,对该数字进行统计:


我们可以看到,这个时候假设是20个任务已经进入了execute方法,但很可能就只有18个在线程池中执行;

而从源码中可以分析得出,调用了Taskqueue.force方法进行强制执行,这个特性也是TaskQueue的一个“乐观”使用线程池的特性:


从代码上可以分析,如果这时候是被拒绝了,说明可能存在并发请求,有并发线程对线程池进行操作,已经同时提交了任务,线程池已经处理了其它的任务

这个时候,一般JDK线程池会配置RejectHandler进行拒绝策略,而我们看到Tomcat的ThreadExecutor就是不成的任务继续回到queue中执行,


这种“回炉”的操作就是Tomcat的RejectHandler策略,通过Taskqueue.force方法,说啥要要把任务给完成,在所不惜;


总结:

本文在上一篇讲解了Tomcat的ThreadExecutor的基础之上,又深入讲解了其中对JDK线程池的改良部分,其中TaskQueue,ThreadLocalLeakPreventionListener 等结合Tomcat的自身场景,给我们日后基于自己应用改造线程池走了很好的样板;

本站公众号
   欢迎关注本站公众号,获取更多程序园信息
开发小院