1. ThreadPoolExecutor概述

ThreadPoolExecutor是Java中并发包(java.util.concurrent)中的一个类,用于实现线程池的功能。线程池可以在程序启动时创建一定数量的线程,用于处理多个任务,并且可以重复使用这些线程,减少线程的创建和销毁带来的开销,提高程序的执行效率。

ThreadPoolExecutor类是ExecutorService接口的一个实现类,它提供了一系列可用于异步执行任务的方法。通过ThreadPoolExecutor,我们可以控制线程池的大小,配置任务的执行策略以及监控线程池的状态。

2. ThreadPoolExecutor的构造方法

ThreadPoolExecutor的构造方法有多个重载的版本,用于创建不同类型的线程池。下面是其中一个常用的构造方法:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
                              long keepAliveTime, TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

2.1 参数解释:

  1. corePoolSize:核心线程数,即线程池中保留的线程数量。
  2. maximumPoolSize:最大线程数,线程池中允许的最大线程数量,包括核心线程和非核心线程。
  3. keepAliveTime:非核心线程的空闲时间,当线程池中的线程数量超过corePoolSize时,如果一个线程在keepAliveTime时间内没有执行任务,就会被终止。
  4. unit:空闲时间的单位。
  5. workQueue:用于存放待执行任务的阻塞队列。
  6. threadFactory:创建线程的工厂。
  7. handler:当线程池和任务队列都满了,无法执行新的任务时,会触发RejectedExecutionHandler,handler用于处理被拒绝的任务。

3. ThreadPoolExecutor的执行过程

3.1 提交任务:当一个任务被提交给ThreadPoolExecutor时,ThreadPoolExecutor会根据当前线程池的状态来确定任务的处理方式。如果线程池中的线程数量小于corePoolSize,会创建一个新的核心线程来执行任务;如果线程池中的线程数量大于等于corePoolSize,但队列未满,会将任务添加到队列中;如果线程池中的线程数量大于等于corePoolSize,并且队列已满,根据线程池的配置和RejectedExecutionHandler对任务进行处理。

3.2 线程池的执行策略:对于任务的执行,ThreadPoolExecutor提供了4种默认的执行策略:

  1. 直接执行(DirectHandoffPolicy):当线程池中的线程数量小于corePoolSize时,任务会直接交给新创建的线程来执行;否则,任务会被添加到队列中。这种策略减少了任务的等待时间,但可能会增加系统的负载。
  2. 无界队列(UnboundedBlockingQueue):任务会无限制地添加到队列中,只要没有超出Integer.MAX_VALUE的限制。这种策略可以确保任务不会丢失,但会导致队列无限增长,可能会耗尽系统的内存。
  3. 有界队列(BoundedBlockingQueue):在有界队列中,任务会按顺序添加到队列中。当队列已满时,新的任务会被拒绝。
  4. CallerRunsPolicy:当线程池和队列都满了,新的任务会被当前线程调用run()方法直接执行。

4. ThreadPoolExecutor的线程调度和监控

ThreadPoolExecutor提供了一系列方法,用于线程池的控制和监控:

  1. prestartCoreThread():预启动一个核心线程,使之在空闲时立即执行任务。
  2. setCorePoolSize()、setMaximumPoolSize():动态设置线程池的核心线程数和最大线程数。
  3. setKeepAliveTime():动态设置非核心线程的空闲时间。
  4. shutdown()、shutdownNow():关闭线程池。
  5. getActiveCount()、getCompletedTaskCount()、getTaskCount():获取线程池的活动线程数、已完成的任务数、总任务数。
  6. allowCoreThreadTimeOut():设置核心线程是否可以超时回收。

通过这些方法,我们可以动态地改变线程池的大小,监控线程池的状态,以及优雅地关闭线程池。