线程池核心参数,线程池工作模型

线程池有 7 个参数,需要重点关注corePoolSizemaximumPoolSizeworkQueuehandler 这四个。

线程池核心参数

ThreadPoolExecutor 是 Java 并发包 java.util.concurrent 中提供的一个灵活的线程池实现。它允许你通过多个参数来定制线程池的行为,以满足不同的应用需求。以下是 ThreadPoolExecutor 的主要构造器参数及其意义:

构造器参数

1
2
3
4
5
6
7
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
  • corePoolSize(核心线程数):线程池中的核心线程数,即使这些线程处于空闲状态,也不会被销毁。除非设置了 allowCoreThreadTimeOut

  • maximumPoolSize(最大线程数):线程池允许的最大线程数。当队列满了,并且已创建的线程数小于 maximumPoolSize,则线程池会再创建新线程来处理任务。

  • keepAliveTime(线程空闲时间):当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间。

  • unit(时间单位):keepAliveTime 参数的时间单位,可以是 TimeUnit 枚举中的任何一个值,如 TimeUnit.SECONDSTimeUnit.MILLISECONDS 等。

  • workQueue(任务队列):用于保存等待执行的任务的阻塞队列。当提交的任务数超过 corePoolSize,这些任务会被保存在队列中,直到线程变得可用。

  • threadFactory(线程工厂):用于创建新线程。这通常用于设置线程名、优先级、是否为守护线程等属性,或者使用自定义的 ThreadFactory 来创建具有特定 UncaughtExceptionHandler 的线程。

  • handler(拒绝策略):当 workQueue 满了,并且已创建的线程数达到 maximumPoolSize 时,线程池无法处理新提交的任务,此时将调用此处理器来处理这种情况。Java 提供了几种预定义的拒绝策略实现,如 AbortPolicy(直接抛出 RejectedExecutionException)、CallerRunsPolicy(调用者运行任务)、DiscardOldestPolicy(丢弃队列中最旧的任务)、DiscardPolicy(不处理,直接丢弃任务)。

执行逻辑

ThreadPoolExecutor 的执行逻辑大致如下:

  1. 当提交一个新任务时,线程池首先会尝试使用当前空闲的核心线程来执行任务。

  2. 如果当前核心线程数已经达到 corePoolSize,新任务会被添加到 workQueue 中等待执行。

  3. 如果 workQueue 已满,并且当前线程数还没有达到 maximumPoolSize,线程池会创建一个新线程来处理任务。

  4. 如果 workQueue 已满,且线程数已经达到 maximumPoolSize,线程池会根据所设置的 RejectedExecutionHandler 来处理新提交的任务。

  5. 当一个线程完成任务时,它会在等待新的任务。如果线程池中的线程数超过了 corePoolSize,并且这些线程在 keepAliveTime 内没有接到新的任务,它们会被终止。这有助于减少资源消耗。

通过调整这些参数,你可以根据应用程序的具体需求来优化线程池的性能。例如,对于 CPU 密集型任务,你可能希望将 corePoolSizemaximumPoolSize 设置为相同的值,以充分利用系统的计算能力。对于 I/O 密集型任务,你可能希望设置一个较大的 maximumPoolSize,以便在等待 I/O 操作完成时,可以处理更多的任务。


ThreadPoolExecutorcorePoolSize 设置为 0 时,其执行逻辑会有所不同。以下是 corePoolSize 为 0 时的执行逻辑概述:

  1. 提交新任务:当向线程池提交一个新任务时,由于 corePoolSize 为 0,线程池不会立即创建核心线程来处理这个任务。

  2. 判断任务队列:接下来,线程池会检查任务队列(workQueue)是否已满。如果队列未满,新任务将被放入队列中等待执行。

  3. 创建新线程:如果任务队列已满,并且线程池中的当前线程数还没有达到 maximumPoolSize,线程池会创建一个新线程来处理任务。尽管 corePoolSize 为 0,但线程池仍然会根据需要创建新线程,直到达到 maximumPoolSize 的限制。

  4. 拒绝策略:如果任务队列已满,且线程数已达到 maximumPoolSize,那么线程池会根据设置的拒绝策略(RejectedExecutionHandler)来处理新提交的任务。可能的处理方式包括直接抛出异常、调用者运行任务、丢弃最旧的任务或不处理直接丢弃任务。

需要注意的是,尽管 corePoolSize 为 0,但线程池仍然可以创建新线程来处理任务,只要任务队列已满且当前线程数未达到 maximumPoolSize。这与 corePoolSize 大于 0 的情况不同,在 corePoolSize 大于 0 时,线程池会优先使用核心线程来处理任务。

此外,由于 corePoolSize 为 0,线程池中没有固定的核心线程,所有线程都是根据需要动态创建的。这意味着在没有任务提交时,线程池中的线程可能会被销毁(如果它们超过了 maximumPoolSize 并且在 keepAliveTime 内没有接到新任务),从而节省系统资源。

总的来说,当 corePoolSize 为 0 时,线程池的执行逻辑更加灵活,可以根据任务的提交情况和队列的状态动态地创建和销毁线程。这种配置通常适用于那些任务提交频率不高,或者需要快速响应的任务场景。