之前我们提到过线程池的实现类就是ThreadPoolExecutor,它是继承自AbstractExecutorService类的,实现了ExecutorService接口。
其实线程池的参数指的就是ThreadPoolExecutor的成员属性,这些属性决定了线程池本身。
来到ThreadPoolExecutor的构造器,发现这里的七个参数,这时候我们不明白这些都是什么含义,先上一个总结图,然后再一个一个说明:
银行有很多服务窗口,有时窗口是满的,有时部分窗口休息不开放。
将整个银行看成一个线程池,每个进入的客户就是一个个任务,工作人员就是线程池中的线程,那么:
corePoolSize可以理解为线程池中的常驻线程数量,也就是一直在上班的员工,当调用threadPool.execute方法,这些线程就会对任务队列中的一个一个任务进行操作。
这个可以理解为银行中柜台的个数,也就是线程池中的最大容量,当所有工作人员都在柜台开始工作,此时柜台已经被占满了。
任务队列可以理解为正在排队的客户,银行一般都有很多椅子,这就是我们的任务队列,区别在于我们是拿号按照指定次序到对应窗口,而程序中是工作线程去找任务进行执行。
任务队列的分类:
ArrayBlockingQueue 是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。LinkedBlockingQueue 一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列SynchronousQueue 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool(5)使用了这个队列。PriorityBlockingQueue 一个具有优先级的无限阻塞队列。生成工作线程的工厂对象,一般用默认的即可
当队列已满,且工作线程数大于等于maximumPoolSize,此时handler会说明如何执行多出来的Runnable任务。这就相当于,当银行柜台所有员工都在上班,且椅子都满了,如何处理这个客户的请求问题。
public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }其本身是一个接口,定义的方法可以看出它就是要求处理Runnable任务的。JDK有四种默认拒绝策略:
TimeUnit其实就是Java8后引入的工具类,表示时间的。keepAliveTime定义了一个时间,这个时间是用来销毁多余的工作线程的,什么是多余的工作线程呢?
对应到银行的例子,其实就是今天本来有两个员工上班(核心线程),干着干着发现客户(RunnableTask)太多,于是就会通知其他员工来上班,等到其他加班的人空闲到一定时间,就让他们回家休息,这就是keepAliveTime。