ThreadPoolExecutor线程池知识总结

项目里应该常用这个类吧,为了避免频繁的创建线程和销毁线程,如果线程太多也会存在线程之间竞争资源的问题,我们可以通过线程池来避免这些问题

ThreadPoolExecutor 这个是阿里java开发文档上指定的创建线程池的方式,为了避免使用Executors过多的隐藏了线程池的特点,在此需要手动的配置一下线程池的参数。

ThreadPoolExecutor 最多可配置7个参数,分别是

int corePoolSize  线程池核心线程数
int maximumPoolSize  线程池最大线程数(核心线程数+非核心线程数)
long keepAliveTime  线程闲置状态存活时间
TimeUnit unit   线程闲置状态存活时间单位
BlockingQueue<Runnable> workQueue  工作队列
ThreadFactory threadFactory 创建线程的方式
RejectedExecutionHandler handler 拒绝策略

下面介绍一下每个参数的含义

corePoolSize:核心线程数最大值,当当前线程池的线程数小于该值是创建的线程属于核心线程,大于该值时属于非核心线程。核心线程会一直存活于线程池里,即使什么事情也不干,但如果allowCoreThreadTimeOut设置为true的时候,线程池就可以将核心线程在到达闲置最长时间后回收销毁。

maximumPoolSize:线程池最大线程数,值 = 核心数 + 非核心数,非核心线程在闲置到最大闲置存活时间后会被销毁回收。但是核心线程只有在allowCoreThreadTimeOut = true的时候才会回收销毁

keepAliveTime :线程闲置最长存活时间

unit:线程闲置最长存活时间的单位,是个枚举值


public enum TimeUnit {
    /**
     * Time unit representing one thousandth of a microsecond
     * 纳秒 
     */
    NANOSECONDS

    /**
     * Time unit representing one thousandth of a millisecond
     * 微秒 
     */
    MICROSECONDS

    /**
     * Time unit representing one thousandth of a second
     * 毫秒
     */
    MILLISECONDS

    /**
     * Time unit representing one second
     * 秒
     */
    SECONDS

    /**
     * Time unit representing sixty seconds
     * 分
     */
    MINUTES

    /**
     * Time unit representing sixty minutes
     * 时
     */
    HOURS

    /**
     * Time unit representing twenty four hours
     * 天
     */
    DAYS

workQueue:工作队列,用于保存等待执行的任务的阻塞队列。当所有核心线程都在执行的时候,多余的任务就会存放在队列里,如果队列满了就会创建非核心线程去执行任务。常用的队列有以下几种:

1. LinkedBlockingQueue:基于链表结构的队列,基本属于无限长度,最大值为Integer最大值,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue,这个是用的最多的工作队列了,可以存放很多任务,不过需要注意的是一旦采用此队列,你设置的maximumPoolSize就无效了,因为工作队列基本无限,所以队列就不会满,也就不会去创建非核心线程去执行任务,总线程数也就不会大于corePoolSize。

2、SynchronousQueue:一个不存储元素的阻塞队列,因为不存储任务,所以当核心线程都在工作的时候,必须需要创建新的非核心线程去执行任务,然而这时候maximumPoolSize就需要足够大,防止线程池提示无法创建新线程,Executors.newCachedThreadPool就是采用此队列实现的,设置了maximumPoolSize = Integer.MAX_VALUE

3、ArrayBlockingQueue:有界的队列,基于数组实现,该队列可能存放满。就会通过创建非核心线程执行任务,但是总线程数达到maximumPoolSize后也会出现异常,不怎么用

4、DelayedWorkQueue:延时队列,Delayed元素的一个*阻塞队列,只有在延迟期满时才能从中提取元素  不怎么用,不熟悉

threadFactory:线程实现方式,这是个接口,可以实现自己的想要的线程实现方式

handler:拒绝策略,当核心线程数无法执行任务,工作队列也满了,也没有多余的非核心线程数去执行任务等等情况,这时候需要对任务有个处理,ThreadPoolExecutor提供了四种拒绝策略。

1、CallerRunsPolicy:直接运行这个任务,不在线程池里执行。
2、AbortPolicy:抛出RejectedExecutionException异常
3、DiscardPolicy:不抛异常,也不会执行这个任务,也没有任何日志记录
4、DiscardOldestPolicy:先检查ThreadPoolExecutor的等待队列,将队头的任务强行取出来再试图将被拒绝的任务提交给线程池执行

另外Executors提供了四种常用线程池,分别是newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool、newScheduledThreadPool。不过一般项目里不让用,都会自己通过ThreadPoolExecutor自己创建。

线程池的总线程数是需要自己去评估大小的,不能盲目的以为线程数越多越好,要考虑服务器的性能去综合考虑最大线程数。可以参考这个公式 最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

上一篇:浙江、江苏推动企业上云 瞄准人工智能的工业效益


下一篇:大数据时代的商业银行数字化转型