线程池核心参数,线程池工作模型
线程池有 7 个参数,需要重点关注corePoolSize、maximumPoolSize、workQueue、handler 这四个。
ThreadPoolExecutor
是 Java 并发包 java.util.concurrent
中提供的一个灵活的线程池实现。它允许你通过多个参数来定制线程池的行为,以满足不同的应用需求。以下是 ThreadPoolExecutor
的主要构造器参数及其意义:
构造器参数
1 | public ThreadPoolExecutor(int corePoolSize, |
corePoolSize(核心线程数):线程池中的核心线程数,即使这些线程处于空闲状态,也不会被销毁。除非设置了
allowCoreThreadTimeOut
。maximumPoolSize(最大线程数):线程池允许的最大线程数。当队列满了,并且已创建的线程数小于
maximumPoolSize
,则线程池会再创建新线程来处理任务。keepAliveTime(线程空闲时间):当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间。
unit(时间单位):
keepAliveTime
参数的时间单位,可以是TimeUnit
枚举中的任何一个值,如TimeUnit.SECONDS
、TimeUnit.MILLISECONDS
等。workQueue(任务队列):用于保存等待执行的任务的阻塞队列。当提交的任务数超过
corePoolSize
,这些任务会被保存在队列中,直到线程变得可用。threadFactory(线程工厂):用于创建新线程。这通常用于设置线程名、优先级、是否为守护线程等属性,或者使用自定义的
ThreadFactory
来创建具有特定UncaughtExceptionHandler
的线程。handler(拒绝策略):当
workQueue
满了,并且已创建的线程数达到maximumPoolSize
时,线程池无法处理新提交的任务,此时将调用此处理器来处理这种情况。Java 提供了几种预定义的拒绝策略实现,如AbortPolicy
(直接抛出RejectedExecutionException
)、CallerRunsPolicy
(调用者运行任务)、DiscardOldestPolicy
(丢弃队列中最旧的任务)、DiscardPolicy
(不处理,直接丢弃任务)。
执行逻辑
ThreadPoolExecutor
的执行逻辑大致如下:
当提交一个新任务时,线程池首先会尝试使用当前空闲的核心线程来执行任务。
如果当前核心线程数已经达到
corePoolSize
,新任务会被添加到workQueue
中等待执行。如果
workQueue
已满,并且当前线程数还没有达到maximumPoolSize
,线程池会创建一个新线程来处理任务。如果
workQueue
已满,且线程数已经达到maximumPoolSize
,线程池会根据所设置的RejectedExecutionHandler
来处理新提交的任务。当一个线程完成任务时,它会在等待新的任务。如果线程池中的线程数超过了
corePoolSize
,并且这些线程在keepAliveTime
内没有接到新的任务,它们会被终止。这有助于减少资源消耗。
通过调整这些参数,你可以根据应用程序的具体需求来优化线程池的性能。例如,对于 CPU 密集型任务,你可能希望将 corePoolSize
和 maximumPoolSize
设置为相同的值,以充分利用系统的计算能力。对于 I/O 密集型任务,你可能希望设置一个较大的 maximumPoolSize
,以便在等待 I/O 操作完成时,可以处理更多的任务。
当 ThreadPoolExecutor
的 corePoolSize
设置为 0 时,其执行逻辑会有所不同。以下是 corePoolSize
为 0 时的执行逻辑概述:
提交新任务:当向线程池提交一个新任务时,由于
corePoolSize
为 0,线程池不会立即创建核心线程来处理这个任务。判断任务队列:接下来,线程池会检查任务队列(
workQueue
)是否已满。如果队列未满,新任务将被放入队列中等待执行。创建新线程:如果任务队列已满,并且线程池中的当前线程数还没有达到
maximumPoolSize
,线程池会创建一个新线程来处理任务。尽管corePoolSize
为 0,但线程池仍然会根据需要创建新线程,直到达到maximumPoolSize
的限制。拒绝策略:如果任务队列已满,且线程数已达到
maximumPoolSize
,那么线程池会根据设置的拒绝策略(RejectedExecutionHandler
)来处理新提交的任务。可能的处理方式包括直接抛出异常、调用者运行任务、丢弃最旧的任务或不处理直接丢弃任务。
需要注意的是,尽管 corePoolSize
为 0,但线程池仍然可以创建新线程来处理任务,只要任务队列已满且当前线程数未达到 maximumPoolSize
。这与 corePoolSize
大于 0 的情况不同,在 corePoolSize
大于 0 时,线程池会优先使用核心线程来处理任务。
此外,由于 corePoolSize
为 0,线程池中没有固定的核心线程,所有线程都是根据需要动态创建的。这意味着在没有任务提交时,线程池中的线程可能会被销毁(如果它们超过了 maximumPoolSize
并且在 keepAliveTime
内没有接到新任务),从而节省系统资源。
总的来说,当 corePoolSize
为 0 时,线程池的执行逻辑更加灵活,可以根据任务的提交情况和队列的状态动态地创建和销毁线程。这种配置通常适用于那些任务提交频率不高,或者需要快速响应的任务场景。