觉得对你有益的小伙伴记得点个赞+关注
后续完整内容持续更新中
希望一起交流的欢迎发邮件至javalyhn@163.com
1. 为什么使用线程池
-
降低资源消耗
- 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
-
提高响应速率
- 因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
-
提高线程的可管理型
- 线程池会根据当前系统特点,对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还会降低系统的稳定性,使用线程池进行统一分配。
2. 线程池的创建
2.1 Executors
Executors.newSingleThreadExecutor();//单线程的线程池,后台从队列里面获取任务,挨个执行
Executors.newScheduledThreadPool();//定时任务的线程池
Executors.newFixedThreadPool();//固定大小的线程池 core=max 都不可回收
Executors.newCachedThreadPool();//core是0 所有线程都可以回收
2.2 ThreadPoolExecutor(推荐使用)
2.3 ThreadPoolExecutor核心参数详解
-
corePoolSize
:核心线程数,线程池创建好以后就已经准备就绪的线程数量,就等待来接收异步任务去执行(除非设置了allowCoreThreadTimeOut,否则会一直存在
) -
maximumPoolSize
:最大线程数量,控制资源 -
keepAliveTime
:存活时间。如果当前线程数量大于corePoolSize,多余的空闲线程(maximunPoolSize - corePoolSize)在终止前等待新任务的最长时间 -
unit
:时间单位 -
BlockingQueue<Runnable> workQueue
:阻塞队列。如果任务有很多,就会将目前多的任务放在任务队列里面,只要有线程空闲,就会去队列里面取出新的任务进行执行 (new LinkedBlockingQueue<>() 默认是Integer的最大值,这里可能会有内存不够的情况,所以一定要指定数量
) -
threadFactory
:线程的创建工厂 -
RejectedExecutionHandler handler
:如果队列满了,就会按照我们指定的拒绝策略执行任务
- DiscardOldestPolicy:丢弃最老的任务
- CallerRunsPolicy:执行run方法
- AbortPolcy:丢弃新任务并且抛出异常 (默认)
- DiscardPolicy:丢弃新任务不抛出异常
2.4 工作顺序
-
线程池创建好,就会准备core数量的核心线程池准备接受任务
-
新的任务进来,用core准备好的空闲线程执行
- 如果core满了,就会将接下来进入的线程放入到阻塞队列中。空闲的core就会自己去阻塞队列里面获取任务执行
- 如果阻塞队列满了,就直接开启新的线程执行,最大只能开到指定的
maximunPoolSize
数量 - 如果都已经超过maximunPoolSize了,
maximunPoolSize - corePoolSize
数量空闲的线程会在keepAliveTime
指定的时间后自动销毁,最终保持到corePoolSize大小 - 如果线程数开到了maxPollSize数量,还有新的任务进来,就会使用reject指定的拒绝策略进行处理
-
所有的线程都是由指定的factory创建的
2.5 最终展示
3. 面试题
一个线程池 core:7 max:20 queue:50 ,100并发进来怎么分配
解析:
- 线程池创建完成,核心线程数个数量的线程开始等待任务,因而7个线程被处理
- 剩下93个线程进入阻塞队列等待,当阻塞队列满了以后,再开20 - 1 = 13个线程来执行,此时还有100-7-50-13=30个线程没有被执行
- 剩下的30个使用拒绝策略执行(默认丢弃)