ThreadPoolExecutor是Java中用于管理线程池的类,它提供了一种方便的方式来执行多线程任务。ThreadPoolExecutor的构造参数有很多,每个参数都有不同的作用和影响,下面我将详细解读每个构造参数,并尽量用通俗的语言解释它们。
首先需要明白,线程是要去执行特定任务的,这些任务通常是特定的代码段,我们需要将代码段封装成一个任务(比如Runnable),将其交给线程去执行任务。
而我们的线程池就装载了一些线程,一旦有任务来临,就可以从线程池中取出线程去执行我们的任务。ThreadPoolExecutor就可以创建出线程池,线程池的创建是需要很多“讲究”的,这些讲究就是我们本文要讲的七大构造参数,如下所示:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize(核心线程数):
这是线程池中始终保持存活的线程数量。
通俗地说,即使没有任务要执行,线程池也会一直保持这些核心线程的存在。
maximumPoolSize(最大线程数):
这是线程池中允许的最大线程数量。
如果当前任务数量超过核心线程数,线程池会创建新的线程,但不会超过这个最大线程数。
keepAliveTime(线程空闲时间):
当线程池中的线程数量大于核心线程数时,多余的线程在空闲时间达到这个值后会被终止并从线程池中移除。
这个时间可以理解为线程的“闲置时间”。
unit(时间单位):
指定了keepAliveTime参数的时间单位,通常是秒、毫秒等。
workQueue(任务队列):
用于存放待执行的任务的队列。
当提交的任务数量大于核心线程数时,超过核心线程数的任务会被放入这个队列中等待执行。
threadFactory(线程工厂):
用于创建新线程的工厂。
可以自定义线程的名称、优先级等属性。
handler(拒绝策略):
当任务数量超过最大线程数且队列已满时,用于决定如何处理新任务的策略。
常见的策略有抛出异常、丢弃任务、阻塞等。
举例分析
假设我们经营一家小餐馆,并且需要管理一组员工来为客人提供服务。
corePoolSize(核心员工数):
这就像是我们餐馆里一直准备好的服务员数量。不论是否有顾客,我们至少需要雇佣2名服务员。
maximumPoolSize(最大员工数):
这是我们餐馆里服务员的最大数量。最多我们可以雇佣4名服务员。
keepAliveTime(员工空闲时间):
这是指服务员在没有顾客需要服务时,可以空闲多久而不被解雇。假设是1小时。
unit(时间单位):
这是用于衡量员工空闲时间的单位,我们使用小时作为单位。
workQueue(任务队列):
这就像是一个顾客等待用餐的队列。当所有的服务员都在忙碌的时候,新的顾客会排队等待。
他们之间的关系及流程如下:
初始时,我们雇佣了2名服务员(corePoolSize),并且有一名顾客(顾客就相当于任务)在餐馆等待。
当更多的顾客进来,如果服务员不够,我们会雇佣新的服务员,但不超过4名(maximumPoolSize)。
如果有一名服务员在1小时内没有服务顾客(keepAliveTime),那么他可能会被解雇,但始终保持2名服务员。
当顾客进来时,他们会排队等待服务,就像排在任务队列中一样。
当有服务员空闲时,他们会从队列中取出下一个顾客,并为他们提供服务,然后返回继续等待。
这就是ThreadPoolExecutor参数之间的流程示例。这个线程池管理着一组服务员(线程),根据工作负载来雇佣和解雇服务员,并将顾客(任务)排队等待服务。
总的来说,任务来临会首先由core线程来执行,就像是餐馆的核心员工。当core已经有任务在身,这时候程序还有其他任务来临时,会进入workQueue队列进行排队等候被执行。程序检测到队列有没被执行的任务时,而core线程正在忙其他的任务,那么就会另开一些新线程来执行队列中的任务。
这些新线程有两个注意点,一个是这些线程在程序中存活多久?这是由keepAliveTime决定的。另一个是程序中的新线程数量最多有几个?这与maximumPoolSize是紧密相关的。
当新线程执行完一个任务时,会检测队列中还有无任务需要执行,如果没有,则进入空闲状态,从此时计时开始,到达keepAliveTime时间之前还没有执行其他任务,那么就关闭此线程。这个线程就被程序所回收了。
maximumPoolSize决定了线程池中最多有几个线程存在,而corePoolSize是自始至终永远存在的线程,所以线程池中最大能另开maximumPoolSize-corePoolSize个线程。
整体运行流程
1、线程池创建,准备好 core 数量的核心线程,准备接受任务
2、新的任务进来,用 core 准备好的空闲线程执行。
(1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队
列获取任务执行
(2) 、阻塞队列满了,就直接开新线程执行,最大只能开到 max 指定的数量
(3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自
动销毁。最终保持到 core 大小
(4) 、如果线程数开到了 max 的数量,还有新任务进来,就会使用 reject 指定的拒绝策
略进行处理
3、所有的线程创建都是由指定的 factory 创建的。