ThreadPoolExecutor的参数与线程池的五个状态

ThreadPoolExecutor,它是Executors.newXxxxx()的返回结果,像Executors.newCachedThreadPool();,它实际上是这个:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

这是FixedThreadPool的:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

所以ThreadPoolExecutor是最为重要的,先了解下它的构造器参数:

public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
                          int maximumPoolSize,//线程池的最大线程数
                          long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                          TimeUnit unit,//时间单位
                          BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
                          ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
                          RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
                           ) {

corePoolSize说明有多少个核心线程,核心线程的策略是添加任务时,目前的核心线程数量小于corePoolSize,就生成一个核心线程放进去核心线程池,并放入Runnable执行。并且,核心线程在任务执行完成后不会销毁,他会一直空转直至再次分配任务。

maximumPoolSize就是最大线程数,注意这个多的线程并不是一有任务来就会创建的,只有当任务队列满了,且已创建的线程数小于maximumPoolSize,线程池才会创建新的线程来执行任务。这也表明了核心线程的地位,只要不是紧急(队列满),核心线程会一直自个去处理。

  • maxPoolSize > 当线程数 >= corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
  • 当线程数 = maxPoolSize,且任务队列已满时,线程池会根据拒绝策略进行处理

keepAliveTime、unit就是如果多余线程空闲了,在这个时间后,就销毁,免得占用资源。

最关键的还是这个workQueue,任务队列。一般而言它有三种选择:SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue。

SynchronousQueue看着像队列,但它不会存任何一个东西,当向队列插入任务时,它会一直阻塞直到有一个空闲线程取走它。如果使用SynchronousQueue,那maximumPoolSize就是表明线程池的线程最大允许数量,可以一直插入新任务直到满了。

LinkedBlockingQueue就是一个真的队列了,可以缓存需要等待的任务。使用LinkedBlockingQueue,如果不输入参数固定长度,队列理论可以无限长,所以不会创建除核心线程以外的线程,所以maximumPoolSize如同虚设(一般设为核心线程数),所以任务可以无限提交,永远不会满除非内存放不下,线程池会按顺序一一执行:此时就是一个生产者消费者模式;如果输入参数固定长度,就和ArrayBlockingQueue类似了。

ArrayBlockingQueue与LinkedBlockingQueue类似,但它是数组实现,所以是有界的。另外,为了同步,它的生产与消费使用的同一把锁;而LinkedBlockingQueue只在确定队列大小时,当队列满了才会加锁:这与数据结构有关。

关于BlockingQueue的研究

拒绝策略有4种,一是丢弃报错,二是丢弃不报错,三是丢弃最老的任务(顺序排第一位的)并提交该任务,四是调用线程(提交任务的线程)直接执行被丢弃的任务。默认是丢弃报错,业务中看业务需求选择。

线程池的五个状态

1、RUNNING

(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。
(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!

2、 SHUTDOWN

(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

3、STOP

(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4、TIDYING

(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5、 TERMINATED

(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值