线程池

Executor:执行者,用来执行一个Runnable

image-20220304203507319 ExecutorService:拓展了Executor,完善了整个任务执行器的所有声明周期方法,这里遵循了接口隔离原则。

image-20220304203539111 AbstractExecutorService主要实现了submit、invokeAny、invokeAll方法,这里使用了模板设计模式,在这些方法中实现了模板代码逻辑,并暴露出一些抽象方法供子类实现
ThreadPoolExecutor 则是具体的线程池的实现
FoorkJoinPool,不同于ThreadPoolExecutor,它具有分解汇总任务,使用很少的线程可以执行很多的任务,非常适合CPU密集型的场景
ThreadPoolExecutor

使用ThreadPoolExecutor
构造器
创建一个ThreadPool供需要提供如下几个参数:

corePoolSize核心线程数,线程池默认的核心线程数,几十超过keepAlive也不会释放线程,他将会一直占用maximumPoolSize最大线程数,最多可以创建的线程数keepAliveTime如果一个线程持续这个时间,就将这个线程归还给操作系统,因为操作系统的线程数量有限,注意归还的是非核心线程unit是keepAliveTime的时间单位workQueue指定任务队列,需要时一个阻塞队列,当来了一个任务时,没有空闲的线程可以处理,就将其放入到任务队列中threadFactory用于产生线程的线程工厂,可以为线程指定名称,一些额外的日志操作handler拒绝策略,如果任务队列也满了,就会进行拒绝策略(比如对未能处理的进行持久化)
拒绝策略
拒绝策略采用策略模式,其策略接口为RejectedExecutionHandler,共有以下几个实现类:
AbortPolicy直接抛出异常拒绝CallerRunsPolicy调用run方法直接在主线程执行,这种方式也称为背压DiscardPolicy内部什么都不做,新的线程将会被忽略 (不可使用)DiscardOldestPolicy会poll掉workQueue的一个最老的任务,然后将当前的任务放入
线程池的状态
线程池的状态由ctl这个数字二进制的前三位存储(后面29位信息用来记录工作线程的数量),他的状态共分为五种,如下:
状态机的转换:

面试重点
ctl 是什么
状态转换的过程
构造函数
拒绝策略
runWorker方法的三个步骤
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 相对于 ThreadPoolExecutor 扩展了 ScheduledExecutorService 接口:
ForkJoinPool
Executors
线程池的工厂/工具类,他有以下几个常用的方法:
SingleThreadExecutor
CachedThreadPool,一般不会使用
FixedThreadPool,固定长度的线程池
ScheduledThreadPool,专为定时任务提供的线程池,使用的不多,应该使用定时任务框架(Quarts)
如何调整线程池的大小
如果线程数量设置的过多,那么他们会竞争稀缺的处理器和内存资源,造成大量的时间浪费在线程的切换上
如果线程数量设置的过少,那么处理器的一些核就无法被充分利用
线程池的短小可以使用下面的公式计算:

image-20220305120916111 推荐使用压测
最后更新于
这有帮助吗?