首先我们要知道什么是线程池?
使用池化技术管理和使用线程的一种机制 本质是多个对象的复用。
线程池的核心组成主要是 ,
1.一个阻塞对列 ,阻塞对列 中放有当前要执行的所有的任务
2.一个包含N个线程的顺序表/数组
线程池的优先有那些?
1.避免线程频繁创建和消耗锁带来的性能开销
2.线程池可以更快速的执行任务,当有任务时可以直接分配线程进行执行
3.线程池有统一调度和管理机制,可以避免线程的争抢;
4.线程池提供更加丰富的功能,可以执行定时任务的线程池
线程池的创建?
线程池创建方法主要有7种(其中6种是通过Executors ,1 种 是通过ThreadPoolExecutor创建的)
1.Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会 在队列中等待;
2.Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
3.Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
4.Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
5.Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
6.Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。
7.ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置
这里我们说下最常用的第七种方法
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,
15,
100,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10));
for (int i = 0; i < 21 ; i++) {
threadPoolExecutor.submit(()->{
System.out.println("线程的名称:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
这是这种方法最基本的创建方式,最少需要5个参数才能将这种线程池创建好
参数一:corePoolSize
核心线程数,线程中始终存活的数
参数二:maximumPoolSize
最大线程数,线程池中允许的最大线程数,当线程任务对列满了之后可以创建的最大线程数
参数三:keepAliveTime
线程最大存活时间
参数四:unit
单位是和参数 3 存活时间配合使用的,合在一起用于设定线程的存活时间
参数五:workQueue
一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全
参数六:threadFactory
线程工厂,主要用来创建线程,默认为正常优先级、非守护线程
参数七:handler
拒绝策略,拒绝处理任务时的策略
上面就是第七种方法的线程池创建时的参数
线程池(第七种线程池)的运行机制
当任务量 比较少的使用线程池提供的核心线程数进行执行
如果当前的任务超过了核心线程数,新任务就会放入任务对列
当任务对列和和核心线程数都满了的时候,新任务来了之后会使用最大线程数来执行任务
当任务对列和最大线程数都已经满了之后,新任务就会执行拒绝策略
拒绝策略
JDK(四种拒绝策略)
-拒绝执行新来的任务并抛出异常(默认拒绝策略)
-可以使用主线程来执行将来的新任务(mian主线程)
-忽略当前任务,但是不报错
-忽略老的任务,也不报错
自定义拒绝策略:根据实际的业务场景自己来处理