一个例子讲明白线程池ThreadPoolExecutor的七大参数-----面试必考

一.线程池的参数指的是什么

在这里插入图片描述
之前我们提到过线程池的实现类就是ThreadPoolExecutor,它是继承自AbstractExecutorService类的,实现了ExecutorService接口。

其实线程池的参数指的就是ThreadPoolExecutor的成员属性,这些属性决定了线程池本身。


二.七大参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

来到ThreadPoolExecutor的构造器,发现这里的七个参数,这时候我们不明白这些都是什么含义,先上一个总结图,然后再一个一个说明:

在这里插入图片描述


三.一个例子

银行有很多服务窗口,有时窗口是满的,有时部分窗口休息不开放。

在这里插入图片描述

将整个银行看成一个线程池,每个进入的客户就是一个个任务,工作人员就是线程池中的线程,那么

corePoolSize 核心线程数:

corePoolSize可以理解为线程池中的常驻线程数量,也就是一直在上班的员工,当调用threadPool.execute方法,这些线程就会对任务队列中的一个一个任务进行操作。


maximumPoolSize 能容纳最大线程数:

这个可以理解为银行中柜台的个数,也就是线程池中的最大容量,当所有工作人员都在柜台开始工作,此时柜台已经被占满了。


workQueue 任务队列:被提交未执行

任务队列可以理解为正在排队的客户,银行一般都有很多椅子,这就是我们的任务队列,区别在于我们是拿号按照指定次序到对应窗口,而程序中是工作线程去找任务进行执行。

任务队列的分类:

  1. ArrayBlockingQueue
    是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
  2. LinkedBlockingQueue
    一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
  3. SynchronousQueue
    一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool(5)使用了这个队列。
  4. PriorityBlockingQueue
    一个具有优先级的无限阻塞队列。

threadFactory 线程工厂:

生成工作线程的工厂对象,一般用默认的即可


handler 拒绝策略:

当队列已满,且工作线程数大于等于maximumPoolSize,此时handler会说明如何执行多出来的Runnable任务。这就相当于,当银行柜台所有员工都在上班,且椅子都满了,如何处理这个客户的请求问题。

public interface RejectedExecutionHandler {

    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

其本身是一个接口,定义的方法可以看出它就是要求处理Runnable任务的。JDK有四种默认拒绝策略:
在这里插入图片描述

keepAliveTime & TimeUnit:

TimeUnit其实就是Java8后引入的工具类,表示时间的。keepAliveTime定义了一个时间,这个时间是用来销毁多余的工作线程的,什么是多余的工作线程呢?

  • 对应到银行的例子,其实就是今天本来有两个员工上班(核心线程),干着干着发现客户(RunnableTask)太多,于是就会通知其他员工来上班,等到其他加班的人空闲到一定时间,就让他们回家休息,这就是keepAliveTime。

四.线程池底层原理总结:

  1. 在创建了线程池后,开始等待请求
  2. 当调用execute()方法添加一个请求任务时,线程池会做出如下判断
  3. 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务
  4. 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列
  5. 如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务
  6. 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略handler来执行
  7. 当一个线程完成任务时,它会从队列中取下一个任务来执行
  8. 当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断:
    如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。
    所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值