ThreadPoolExecutor

ThreadPoolExecutor

线程池有多种实现类,常用的例如 固定大小的FixedThreadPool, 可以复用线程的CachedThreadPool,可以定时的ScheduleThreadPool等等。

线程池结合Executor模式,最终提供了一套简单可用的线程池。

使用线程池一定要注意内存使用,内存的使用和构造ThreadPoolExecutor时候的参数使用有很大关系

查看ThreadPoolExecutor的构造函数可以看到几个核心参数

  • corePoolSize 核心线程数

  • maximumPoolSize 最大线程数

  • keepAliveTime 当一个线程任务完成后的存活时间(超过核心线程的部分)

  • unit keepAliveTime的单位

  • BlockingQueue 当核心线程使用完毕后,之后的任务将会放入到此队列

  • ThreadFactory 线程工厂类

  • RejectedExecutionHandler 当线程数量达到maximumPoolSize之后的拒绝策略

参数详解

其中核心线程数和最大线程数之间的关系也比较重要,核心线程是当任务提交之后一次性创建的,最大线程是队列满了之后继续创建线程的最大值。

流程如下:

一开始,池中将会创建corePoolSize个线程

之后陆陆续续提交任务,池中的corePoolSize个线程都开始了工作。但是任务还在陆陆续续进来,这时候,任务将会被存在BlockingQueue中

之后BlockingQueue也满了,这时候将会继续创建线程,来处理任务。任务还在继续,创建的线程的数量到达了maximumPoolSize的大小,这时,后续的任务将会被reject

所以在设置Queue以及maximumPoolSize参数就需要小心,防止不断存入队列或者最大线程池大小过大

举例

以二元组为一个状态,来看看这个过程中各个参数的变化

举例来说,corePoolSize=5, maximumPoolSize=10, Queue大小为3,任务数为30,前提为任务时间比较长

{corepoolsize, queue_size}

{0, 0} -> {5, 3} -> {6, 3} -> {7, 3} -> {8, 3} -> {9, 3} -> {10, 3}

13号之后的任务被拒绝

再假如 任务数为 12

这个数量变化为:

{corepoolsize, queue_size}

{0, 0} -> {5, 3} -> {6, 3} -> {7, 3} -> {8, 3} -> {9, 3} -> {9, 3}

可以看到是最终是队列满的,线程数量停留在9