线程池学习
一、使用线程池的好处:
1、降低资源的消耗
通过重复利用已经创建好的线程来降低线程创建和销毁的损耗
2、提高响应速度
但线程池中有空闲线程时,接收到新任务可直接执行,不需要再重新创建
3、提高线程的可管理性
可对系统的核心功能和非核心功能进行分块控制,可在特定时间对核心功能进行升级,或者非核心功能块降级
/**
* 七大参数:
* corePoolSize:【核心线程数】【一直存在(除非设置了 {@code allowCoreThreadTimeOut}【允许核心线程超时】)】
* 在线程池中,创建好就可以直接使用的线程数,等待接收异步请求任务直接执行
* maximumPoolSize:【最大线程数】;用于控制资源
* keepAliveTime:【存活时间】。当前的线程数量大于核心【core】线程数,
* 且线程空闲时间超过keepAliveTime则释放(max-core)中的线程
* TimeUnit unit:【存活时间单位】。时分秒
* BlockingQueue<Runnable> workQueue:【阻塞队列】如果任务有很多,核心线程执行剩余的任务都会放在队列中,当有线程空闲时,再从队列中获取
* ThreadFactory threadFactory:【线程的创建工厂】一般都是默认
* RejectedExecutionHandler handler:【拒绝策略】当队列满了之后,按照指定的策略拒绝其余任务
*
* 工作顺序:
*1)、创建线程池,创建好core数量的核心线程,准备接收任务
* 1.1、core满了,就将后面进来的任务放到阻塞队列中。空闲的core会自动去队列中获取任务执行
* 1.2、阻塞队列满了,会开启新线程执行,但最多开到max指定的数量
* 1.3、max也满了的话,会按照RejectedExecutionHandler拒绝策略拒绝任务执行
* 1.4、max执行完之后的话,会在空闲时间keepAliveTime之后释放资源
*/
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
二、线程池七大参数
1、corePoolSize:【核心线程数】
一直存在(除非设置了 {@code allowCoreThreadTimeOut}【允许核心线程超时】)
在线程池中,创建好就可以直接使用的线程数,等待接收异步请求任务直接执行
2、maximumPoolSize:【最大线程数】
用于控制资源,当前最多执行任务的线程数
3、keepAliveTime:【存活时间】
当前的线程数量大于核心【core】线程数,且线程空闲时间超过keepAliveTime则释放(max-core)中的线程
4、TimeUnit unit:【存活时间单位】
时分秒。TimeUnit.SECONDS
5、BlockingQueue workQueue:【阻塞队列】
如果任务有很多,核心线程执行剩余的任务都会放在队列中,当有线程空闲时,再从队列中获取
默认为integer的最大值,默认值可能会导致内存不够,具体根据实际业务指定数量,如:100000
new LinkedBlockingDeque<>(100000)
6、ThreadFactory threadFactory:【线程的创建工厂】
一般都是默认
7、RejectedExecutionHandler handler:【拒绝策略】
当队列满了之后,按照指定的策略拒绝其余任务
三、线程池工作顺序
1)、创建线程池,创建好core数量的核心线程,准备接收任务
1.1、core满了,就将后面进来的任务放到阻塞队列中。空闲的core会自动去队列中获取任务执行
1.2、阻塞队列满了,会开启新线程执行,但最多开到max指定的数量
1.3、max也满了的话,会按照RejectedExecutionHandler拒绝策略拒绝任务执行
1.4、max执行完之后的话,会在空闲时间keepAliveTime之后释放资源
四、JUC拒绝策略方案
一、DiscardOldestPolicy:【拒绝】
在接收到新任务时,将已经在执行的最老任务丢弃
二、AbortPolicy:【拒绝】
将新来的任务直接丢弃,不执行(抛异常)
三、CallerRunsPolicy:【执行】
直接执行方法,不启动线程
四、DiscardPolicy:【拒绝】
将新来的任务直接丢弃,不执行(不抛异常)
五、面试案例
7个核心线程core,20个最大线程max,50个阻塞队列,100个异步请求进来会如何执行
1)、7个核心线程直接执行
2)、50个进入阻塞队列
3)、开启最大线程,再执行13个任务
4)、剩余30个任务根据拒绝策略决定
六、常用的四种线程池
1、Executors.newCachedThreadPool()
core是0,所有线程在空闲时都会被回收
2、Executors.newFixedThreadPool()
固定大小,可指定核心线程数,core=max,所有线程都不可回收
3、Executors.newScheduledThreadPool()
定时任务的线程池
4、Executors.newSingleThreadExecutor()
单线程的线程池,后台从队列里面获取任务,挨个执行