- 我将讲解JUC包下的线程池七大参数,以及一些参数如何去使用。
- 同时本篇文章不做基础理论介绍。
- 测试代码文末。
线程池
int corePoolSize : 最小线程数
最小存活的线程数,或者说固定线程数,通俗点说就是正常上班有2个人
int maximumPoolSize: 最大线程数
最大线程数,也就是上限线程数,通俗点说就是你再多人加班也只有5个工位
上述关系
long keepAliveTime:多余线程存活时间
多的线程多久没工作就死亡,通俗的说就是你本来只有2个人上班,工作突然加多,在来了3个人一起帮忙,做完了那帮忙的见(超过 keepAliveTime 时间)没事情做就下班了。
TimeUnit unit : 时间单位
就是keepAliveTime 的单位,具体单位使用 TimeUnit 枚举类
BlockingQueue workQueue: 阻塞队列
JUC包下很重要的工具,名为阻塞队列,这里是队列的接口,满足接口的队列都可以传入,阻塞队列很多种,不在本文介绍范围内。
ThreadFactory threadFactory : 线程工厂
因为传入的是接口形式,需要通过new Thread(Runalbe runalbe)的形式创建线程等行为。
可以使用第三方的线程创建工程定义线程名字等个性化操作,也可以自己创建一个,也不是很难,实现 ThreadFactory 接口,编写接口方法即可,正常的创建线程,定义属性返回线程
RejectedExecutionHandler handler : 拒绝策略
当超出线程池承受范围该如何处理?这就是拒绝策略,自带的有4种,用户也可以实现RejectedExecutionHandler 接口来自己定义自己 的策略规则。
AbortPolicy : 默认策略 直接抛异常 并且程序没有停止 可以看见5,6号元素不见了
DiscardPolicy : 抛弃最新的元素 可以看到5,6好元素不见了,觉得是最好的方法了
DiscardOldestPolicy : 抛弃最老的任务 即 队列中第一个元素,可以看到下图2,3号元素不见了
CallerRunsPolicy : 下图比较诡异,main线程执行了方法,这是回退策略,谁送它来的谁处理,同时会试线程性能下降,所以5,6号元素由main线程执行
实现RejectedExecutionHandler接口介绍
将以DiscardPolicy为例子进行介绍
很简单,这个就是不做任何处理,没有理会这个Runable任务
属性搭配详解
本文最重要的3个参数是 阻塞队列 和 最小线程数 和 最大线程数 的关系
- 默认线程池一个不用,因为默认线程池使用巨大空间界限的 LinkedBlockingDeque 会让后果很严重,就像10多亿人一起排队,多恐怖(可以看看源码,这里就不拿出来了)
- 最大线程数应该根据计算机核素定制,超出计算机支持的核素太多将会有大量的线程上下文切换,浪费性能。
- 当 最小线程数 + 队列空间 能满足需求,将不会开启新的线程
- 当 最小线程数 + 队列空间 < 任务数量 将开启新的线程进行处理
- 当 最大线程数 + 队列空间 < 任务数量 将开启线程池第7个参数 拒绝策略
插播介绍提交方式区别
submit() 和 execute()
submit 是有返回值的,具体将涉及其他领域(Future) ,相配合的是 Callable接口
execute 是无返回值的
在插播一条
shutdown() : 线程池如果不停止,他会一直在跑着程序,在等待任务加入
代码
public class java {
public static void main(String[] args) throws Exception {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
3,
1L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
for(int i = 0; i < 7 ; i++){
final int a =i;
executor.execute(()->{
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"\t 我运行了 "+ a);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
}
}