目录
3. 丢弃队列中的头结点任务 ——> 最先进入队列的任务 DiscardOldestPolicy
4. 由主线程去执行这个任务 CallerRunsPolicy
线程池的作用
线程的创建需要时间,如果每次使用新线程时,都去创建,是比较耗时的。但如果将线程提前创建好,放进池子内,用的时候直接去从池子里去取,就可以省略创建线程的时间。
用空间换取时间 !!
使用线程池的意义
-
节省时间(架构)
-
便于管理线程(管理)
通过线程池,可以规定线程的名字 ,再了解这个线程池当中有哪些线程执行了哪些任务,通过日志可以快速定位问题。
阿里规范规定:只要使用多线程,就必须要用线程池管理
线程池的几个重要参数
-
最小线程数(1):
项目启动时,初始化的线程数
-
核心线程数(8):
当线程池的线程都忙碌时,再进入新的任务时,由最小线程数扩容到核心线程数
ps: 扩容 —— > 在线程池新创建几个线程
注意!!!
扩容创建新线程时,是一个一个建立的,不是同时创建好几个。
一般设置为 cpu的核数
cpu的核数 —— 代表着同一时刻,多少个线程可以同时运行
-
队列大小(1000):
(先进先出)当线程数达到核心线程数,再进入的任务就会进到队列。
队列的分类:
如果队列无限大,那么就能保证执行顺序了
-
最大线程数(8):
如果线程池的线程数达到核心线程数,且队列也满了,又有新任务。
那么,在线程池内创建新线程来执行这个新任务,直到线程数达到最大线程数。
需要注意的是!!!!
新创建的线程处理的任务不是队列中的任务,而是优先执行这个新分配的任务。
一般设置为 cpu的核数 *2
cpu的核数 —— 代表着同一时刻,多少个线程可以同时运行
-
⏱存活时间:
当线程超过一定时间不执行任务,处于空闲状态,线程池会将部分线程回收,直到线程数达到核心线程数。
拒绝策略(4种)
如果队列满了,线程数达到最大线程数,又有新任务,那么执行拒绝策略。
1. 报错,抛异常 AbortPolicy
告诉开发者这个任务线程池执行不了,由开发者决定是否需要丢弃
抛出异常,中止任务。
抛出拒绝执行 RejectedExecutionException 异常信息。
线程池默认的拒绝策略,必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行
2. 丢弃当前任务 DiscardPolicy
3. 丢弃队列中的头结点任务 ——> 最先进入队列的任务 DiscardOldestPolicy
丢弃队列最老任务,添加新任务。
当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
4. 由主线程去执行这个任务 CallerRunsPolicy
使用调用线程执行任务。
当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。
一般并发比较小,性能要求不高,不允许失败。
但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
一般情况下,前三种都会有丢弃任务的风险,但是性能比较好。
第四种最为稳妥。
❗❗❗❗在创建线程池的时候,要结合具体的业务,来规划这些参数 (如何规划很重要)
线程池的执行顺序:最先派给线程池的任务一定最先执行❌❌❌❌❌
原因参考一下 最大线程数那里
若是想保证顺序,则使用无界队列