文章目录
- 线程池使用及优势
- 线程池的3个常用方式
- 架构说明
- 编码实现
- 线程池7大核心参数入门简介
- 线程池7大参数深入介绍
- 线程池底层工作原理
- 线程池的拒绝策略理论讲解
- 实际工作中实际使用哪一种线程池
- 线程池的手写改造和拒绝策略
- 线程池配置合理线程数
线程池使用及优势
只要是new thread,就会产生资源的消耗,就需要GC来回收,多核时代,硬件上已经支持多核心处理多个任务,而不是一个核心进行上下文的切换。想一下spring,需要对象,是不需要new的,因为是依赖注入,提前在容器里新建好了。
线程池的3个常用方式
架构说明
线程池的底层就是ThreadPoolExecutor。扩展说明:数组,集合,线程池都有一个屁股后面加s的辅助工具类。
编码实现
ScheduledThreadPool:是带调度的线程池,可以执行定时任务。
WorkStealingPool:是java8的新特性。
主要有3种类型的线程池,自己知道是5种就行,加上上面那2种。
java中的第四种(继承thread、实现runable,实现callable,线程池)使用线程的方式—线程池。特性:一池固定线程,一池一线程,一池多线程,分别对应上面三种,看名字就可以对上了。
池化资源,关闭比使用更重要!
凡是做并发系统,必然有池。
执行结果:不过多少人,最多同时支持5个在线,控制了并发,同时任务被积攒。没有拒绝。
一池一线程是一池固定线程的特殊情况。代码如下:
运行结果:
一池多线程,当出现并发的时候,根据处理的情况,弹性新建线程。
执行结果会根据并发和处理情况,新建线程。
看一下源代码:
底层代码的核心是ThreadPoolExecutor。
逐一分析:针对固定线程线程池。
线程池的核心:ThreadPoolExecutor和阻塞队列,阻塞队列决定了特性。
线程池7大核心参数入门简介
综合看一下ThreadPoolExecutor:
可以看到常见的五大参数。实际上是有7个。可以看一下ThreadpoolExecutor的源码,构造方法有7个参数。
7参构造方法如下:
线程池7大参数深入介绍
核心数:当值窗口,最大数:银行的最大处理窗口数。空闲线程的存活时间是3.4两个参数。5是来不及处理的任务的存放区,相当于候客区。6是线程工厂,用默认的即可。7是拒绝策略,当处理窗口全开,然后候客区也满了,就需要拒绝新的任务的添加了。
具体的触发逻辑,默认开2个窗口(核心线程数),
线程池的执行逻辑,线程池建立,就会有核心数个线程被创建出来等待任务的提交,核心线程被使用之后,新来任务就放在阻塞队列中,如果阻塞队列也满了,说明业务量激增,线程池会增加线程直到等于max(第二个参数),处理完业务峰值之后,如果增加的线程在规定时间(3.4个参数)内没有分配到任务,则会被销毁,释放资源。如果,业务一直增加,线程数到达了最大,阻塞队列也满了,则开始拒绝策略,默认有4种。第六个参数是创建什么样的线程,一般用默认的就行。
线程池底层工作原理
线程池的拒绝策略理论讲解
是什么:
拒绝策略有4种:
实际工作中实际使用哪一种线程池
正确答案是:一个都不用。
阿里巴巴手册:规定不允许new 线程的同时,不允许使用默认的。因为会oom。这就是不能用的原因!
线程池的手写改造和拒绝策略
实现下图的线程池:
2核心数,5最大数,5s的空闲时间,赋初值3的阻塞队列(不赋初值是21亿)。
线程工厂用默认的:
饱和以后的拒绝策略:使用默认的Abort策略。
最终效果如下:
这个线程池支持的最大线程数是(max+阻塞队列size)8,设置9个线程就爆炸了:
看一下拒绝策略:
默认的这种一旦超出承受能力就报异常,生产肯定不能用。
第二种拒绝策略测试代码:
运行结果:10个请求没有爆炸。
类似去银行,银行满了之后,问顾客从哪里来,可以再回去之前的银行试试。这就是策略二的调节机制。
最后发现是主线程帮着执行了一个任务。
最后这两种都是丢弃,个人很不建议使用,不允许丢失请求的。
线程池配置合理线程数
核心线程数,最大线程数如何配置才合理呢?
根据业务去考虑,CPU密集型还是IO密集型。
io密集型的例子:比如不停的从数据库里面读取。
第一种:
第二种:
这里面说的是最大线程数,核心线程数等于0都可以(缓冲线程池底层的初始值就是0).