天天看点

ThreadPoolExecutor运行机制

最近发现几起对threadpoolexecutor的误用,其中包括自己,发现都是因为没有仔细看注释和内部运转机制,想当然的揣测参数导致,先看一下新建一个threadpoolexecutor的构建参数:

public threadpoolexecutor(int corepoolsize,  

                          int maximumpoolsize,  

                          long keepalivetime,  

                          timeunit unit,  

                          blockingqueue<runnable> workqueue,  

                          threadfactory threadfactory,  

                          rejectedexecutionhandler handler)  

看这个参数很容易让人以为是线程池里保持corepoolsize个线程,如果不够用,就加线程入池直至maximumpoolsize大小,如果还不够就往workqueue里加,如果workqueue也不够就用rejectedexecutionhandler来做拒绝处理。

但实际情况不是这样,具体流程如下:

1)当池子大小小于corepoolsize就新建线程,并处理请求

2)当池子大小等于corepoolsize,把请求放入workqueue中,池子里的空闲线程就去从workqueue中取任务并处理

3)当workqueue放不下新入的任务时,新建线程入池,并处理请求,如果池子大小撑到了maximumpoolsize就用rejectedexecutionhandler来做拒绝处理

4)另外,当池子的线程数大于corepoolsize的时候,多余的线程会等待keepalivetime长的时间,如果无请求可处理就自行销毁

内部结构如下所示:

ThreadPoolExecutor运行机制

从中可以发现threadpoolexecutor就是依靠blockingqueue的阻塞机制来维持线程池,当池子里的线程无事可干的时候就通过workqueue.take()阻塞住。

其实可以通过executes来学学几种特殊的threadpoolexecutor是如何构建的。

public static executorservice newfixedthreadpool(int nthreads) {  

    return new threadpoolexecutor(nthreads, nthreads,  

                                  0l, timeunit.milliseconds,  

                                  new linkedblockingqueue<runnable>());  

}  

newfixedthreadpool就是一个固定大小的threadpool

public static executorservice newcachedthreadpool() {  

    return new threadpoolexecutor(0, integer.max_value,  

                                  60l, timeunit.seconds,  

                                  new synchronousqueue<runnable>());  

newcachedthreadpool比较适合没有固定大小并且比较快速就能完成的小任务,没必要维持一个pool,这比直接new thread来处理的好处是能在60秒内重用已创建的线程。

其他类型的threadpool看看构建参数再结合上面所说的特性就大致知道它的特性