前言:
在面试过程中,我们可能会被面试官经常问到有关线程池和线程池参数的相关问题,如果对于这些问题,你的心中没有明确的答案,那么在看完本篇博客后,相信你将会有所收获!
定义:corePoolSize 代表的是核心线程数,也就是正常情况下创建工作的线程数,这些线程创建后并不会消除,而是一种常驻线程
注意:核心线程数设置太大会浪费系统资源,设置过小导致线程频繁创建
定义:maxmumPoolSize代表的是最大线程数,它与核心线程数相对应,表示最大允许被创建的线程数
注意:比如当前任务较多,将核心线程都用完了,还无法满足需求时,此时就会创建新的线程,但是线程池内的线程总数不会超过最大线程数
定义:keepAliveTime 表示超出核心线程之外的线程空闲存活时间;
如果超出核心线程数的部分线程,空闲时间达到keepAliveTime值时 (可以通过使用setKeepAliveTime来设置空闲时间),则线程会被销毁掉 (直到剩下核心线程数个线程为止)
注意:
TimeUnit是keepAliveTime的时间单位
定义:
workQueue表示缓存队列,用来存放待执行的任务;当请求任务数大于核心线程数时,线程进入阻塞队列 (BlockingQueue)
使用:
定义:threadFactory实际上是一个线程工厂,用来生产同一个组内的线程来执行任务
作用:
主要用于设置生成的线程名称前缀,是否为守护线程以及优先级等
设置有意义的名称前缀有利于在进行虚拟机分析时,知道线程是由哪个线程工厂创建的
使用:
定义:handler表示执行拒绝策略对象
作用:当任务缓存达到上限时 (即超过workQueue参数能存储的任务数) ,然后就执行拒绝策略,可以看做简单的限流保护
使用:分两种情况
有四种拒绝策略:这些拒绝策略都是ThreadPoolExecutor (线程池执行器) 的方法
AbortPolicy:丢弃任务,并抛出 RejectExecutionException (拒绝执行异常)
CallerRunsPolicy:该任务被线程池拒绝,由调用execute方法的线程 (即提交任务的线程) 的处理该任务
DiscardOldestPolicy:抛弃队列最前面的任务,然后重新提交被拒绝的任务
DiscardPolicy:丢弃任务,不过不会抛出异常
总结:当线程池的任务缓存队列 (workQueue) 已满,并且线程池中的线程数目达到最大线程数 (maximumPoolSize) ,如果还有任务到来就会采取拒绝策略
就好比一个企业里有10个正式员工的名额 (相当于核心线程数为10) ,最多招收15个员工 (相当于最大核心线程数为15),如果任务超过正式工人数 (即任务数大于核心线程数),老板 (相当于线程池) 不是首先扩招员工 (即创建新线程),而是将任务进行积压和推迟 (即先放到阻塞队列中去);
让10个员工先将手头工作做完后,然后再去执行推迟的任务 (这样做成本相对低一些),如果推迟的任务量超出了员工的处理能力范围 (即阻塞队列满了),但是老板 (线程池) 发现还有5个招收员工的名额 (相当于最大线程数大于核心线程数),因此老板开始招收临时工 (即创建临时线程) 来协助完成任务;
如果正式工加上临时工 (即核心线程加上临时线程) 还是无法完成任务,但是老板 (线程池) 发现公司已经没有资金再招收新员工了 (即阻塞队列已满并且线程池内线程数超过最大线程数),那么老板会拒绝接收新的任务 (即线程池执行拒绝策略)
//创建缓存线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,ew SynchronousQueue<Runnable>());
}
//创建定时单线程执行器
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
//创建单线程执行器
public static ExecutorService newSingleThreadExecutor() {
//new LinkedBlockingQueue()表示workQueue参数
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
//创建定长线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
//LinkedBlockingQueue(链表有界阻塞队列)的无参构造
public LinkedBlockingQueue() {
//最大线程数是:Integer.MAX_VALUE
this(Integer.MAX_VALUE);
}
//LinkedBlockingQueue的有参构造(参数为整型的capacity(容量)
public LinkedBlockingQueue(int capacity) {
//如果容量小于等于0.就抛出一个IllegalArgumentException(传递不正确参数异常)
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
//创建新节点,头尾值相等
last = head = new Node<E>(null);
}
注意:
好了,今天有关线程池和线程池参数的学习就到此结束了,欢迎大家学习和讨论!
参考视频链接:
https://www.bilibili.com/video/BV1Eb4y1R7zd (B站UP主程序员Mokey的Java面试100道)