线程池的特点,优势,创建
特点
用线程池控制运行线程的数量, 将处理中的线程任务放入队列, 线程创建后启动这些任务, 当线程超出最大数量的时候, 进入队列排队, 等其他线程执行完毕,再从队列中取出任务执行.
优势
- 降低资源消耗, 重复利用线程, 降低线程创建与销毁的消耗
- 提供响应速度, 当任务到达时, 任务不需要等待线程创建, 可以立即执行
- 提高线程管理, 统一分配, 调优, 监控
- 合理使用线程池可以防止处理OOM问题
创建
阿里编码规范.png
ThreadPoolExecutors线程池7大参数
- corePoolSize: 线程池中的核心线程数
- maximumPoolSize: 最大线程数, 必须大于1
- keepAliveTime: 多余的空闲时间
- unit: keepAliveTime单位
- queueCapacity: 任务队列
- threadFactory: 线程池中线程工厂
- rejectedExecutionHandler: 拒绝策略
ThreadPoolExecutors线程池4种拒绝策略
- AbortPolicy(默认): 直接抛异常
- CallerRunsPolicy: "调用者运行"一种调试机制, 将任务返回调用者
- DiscardOldestPolicy: 抛弃队列中等待最久的任务
- DiscardPolicy: 直接丢弃任务
ThreadPoolExector线程池原理分析
public class ThreadPoolExecutorTest {
private static ThreadPoolExecutor executor =
new ThreadPoolExecutor(
2, // 核心线程数2
5, // 最大线程数5
4,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(4)); // 队列数4
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i < 15; i++) {
final String b = String.valueOf(i);
TimeUnit.MILLISECONDS.sleep(100);
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + ": " + b);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
TimeUnit.SECONDS.sleep(20);
}
}
执行结果.png
线程池工作原理.png
线程池合理配置线程数
1)根据几个值来决定
(1) tasks: 每秒的任务数, 假设100 ~ 1000
(2) taskcost: 每个任务花费时间: 假设0.1s
(3) responsetime: 系统允许最大响应时间, 假设1s
2)根据8020定律, corePoolSize计算:
任何一组东西中,最重要的只占其中一小部分,约20%,其余80%尽管是多数,却是次要的,因此又称二八定律
corePoolSize = tasks* taskcout = (100 ~ 1000) * 0.1 = 10 ~ 100
8020定律, 核心线程数为20
3)queueCapacity计算:
任务队列的长度要根据核心线程数,以及系统对任务响应时间的要求有关。队列长度可以设置为
queueCapacity = corePoolSize / taskcost * responsetime = 20 / 0.1 * 1 = 200
注: 若将队列长度设置为Integer.MAX_VALUE,将会导致线程数量永远为corePoolSize,再也不会增加,当任务数量陡增时,任务响应时间也将随之陡增
4)maxPoolSize计算:
当系统负载达到最大值时,核心线程数已无法按时处理完所有任务,这时就需要增加线程
maxPoolSize = (max(sasks) - queueCapacity) * taskcost = (1000 -200) * 0.1 = 80
- rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
6)keepAliveTime和unit采用默认通常能满足
合理创建线程池
ThreadPoolExecutor executor =
new ThreadPoolExecutor(
20, //核心线程数
80, //最大线程数
1, // 多余的空闲时间
TimeUnit.SECONDS, //多余的空闲时间单位
new ArrayBlockingQueue<>(200) //队列长度
,new ThreadFactoryBuilder().setNameFormat("xx-pool-%d").build(), //创建
new ThreadPoolExecutor.DiscardPolicy() //处理策略
);