线程池是用于管理及复用线程的一种机制。通过自定义线程池的参数,可以根据业务需求来灵活地控制线程池的大小、线程的存活时间、任务队列的大小等参数。以下是自定义线程池的一些参数及其含义:
- 核心线程数(corePoolSize):线程池维护的最小线程数量,在没有任务执行时依然存在。当任务到达时,会立即创建线程执行任务。
- 最大线程数(maximumPoolSize):线程池维护的最大线程数量,如果队列已满,则创建的新线程数量不会超过最大线程数。
- 空闲线程存活时间(keepAliveTime):当线程池中所有线程都处于空闲状态时,超过这个时间的线程将被终止并消失。
- unit: keepAliveTime 的单位。
- 任务等待队列(BlockingQueue):用于存储还未执行的任务,当线程池中所有线程都在执行任务时,新的任务将被存储在队列中等待执行。FIFO
- 线程工厂(ThreadFactory):用于创建新线程的工厂类。
- handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。
参数如何设置合理:
一般情况下,可以根据 CPU 核心数来设置核心线程数。如果任务是CPU密集型的,可以设置核心线程数等于CPU核心数,以尽量利用系统的处理能力。如果任务是IO密集型的,可以设置核心线程数稍微多一些,以充分利用IO操作的等待时间。
线程池的执行任务流程如下:
- 当有新任务需要执行时,首先会判断当前线程数是否达到核心线程数,如果没有,则立即创建新线程执行任务。
- 如果线程数已达到核心线程数,并且任务队列未满,则将任务加入队列等待执行。
- 如果线程数已达到核心线程数,并且任务队列已满,但是线程数量未达到最大线程数,则会再次创建新线程执行任务。
- 如果线程数已达到最大线程数,并且任务队列已满,则会根据指定的拒绝策略进行处理。
常见阻塞队列(等待队列):用来保存等待执行任务的队列
1.ArrayBlockingQueue 基于数组结构的有界阻塞队列,按FIFO排序任务
2.LinkedBlockingQueue 基于链表结构的阻塞队列,按FIFO排序任务。吞吐量通常要高于ArrayBlockingQueue
3.SynchronousQueue 一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue
4.PriorityBlockingQueue 具有优先级的无界阻塞队列
设计等待队列的目的:
设计等待队列是为了避免线程池中的所有线程都处于忙碌状态,导致新的任务无法得到及时的处理。通过等待队列,可以将任务存储在队列中等待执行,保证了任务的及时处理。同时,等待队列中存储的任务还可以避免创建过多的线程,从而节省了系统资源。当然,如果任务队列设置的太小,则会快速填满队列,导致新任务被拒绝,因此需要根据实际业务情况合理设置队列的大小。
执行拒绝策略的前提条件:一旦任务数> maxPoolSize+queueSize
拒绝策略:
1.AbortPolicy 默认策略,直接拒绝,抛出异常
2.DiscardPolicy 直接拒绝,不抛出异常
3.DiscardOldestPolicy 直接丢弃等待最久的任务,将最新的任务加入到阻塞队列中
4.CallerRunsPolicy 由当前线程执行任务时,所在的线程来执行此任务