线程我相信大家都使用过,但是在某些场景下,需要重复的创建线程,跑任务然后销毁线程,而线程是一种很贵的资源,创建线程跟销毁线程非常的消耗性能。那么为了减少这种消耗,就有了线程池这种东西。线程池就是线程组成的池子,你可以从这个池子里获取线程,用完后放回去,而减少了线程的频繁创建跟销毁。
创建线程池ThreadPoolExecutor的最完整的构造函数有7个参数
![](https://img.haomeiwen.com/i18159984/5a9a387b849c9fa7.png)
参数分别为:
1.corePoolSize:核心线程数,线程池的线程数量,即使线程是闲置的
2.maximumPoolSize:最大线程数,线程池中所允许的最大的线程数量
3.keepAliveTime:存活时间,如果线程的数量大于核心线程数,那么这就是多于核心线程数的线程的最大闲置时间
4.unit:存活时间的单位
5.workQueue:工作队列,当线程大于核心线程数时,多余的任务会放到这个队列中。如果队列满了,就会往最大的线程数开启线程
6.ThreadFactory:创建线程的工厂
7.RejectedExecutionHandler:拒绝策略,如果队列跟最大线程数都满了,那么对接下去进来的任务就执行拒绝策略。
接下来我们就来看一下代码:
![](https://img.haomeiwen.com/i18159984/94e6a0b2c1eb74d0.png)
1.如果当前的工作线程数少于核心线程数,就增加线程去执行任务,如果判断完当前工作线程小于核心线程数之后,增加线程失败(可能是因为核心线程数已满),就返回false,重新计算一下当前的工作线程数。
2.然后判断一下线程池是否在运行,能否放到队列里。如果为是,重新判断一下当前的线程数量,如果线程池已经停止工作,就将队列移除,并且执行拒绝策略。如果有效线程数为0,则新增线程(这种情况对应于核心线程数为0的情况),
3.添加线程失败的话(线程池停止了或者队列满了,最大线程数也满了),就执行拒绝策略
我们来看一下addWorker方法
![](https://img.haomeiwen.com/i18159984/514b5e15615b9b04.png)
1.进行自旋并进行判断,如果线程池已关闭以及线程池正在关闭并且提交的任务为null并且任务队列不为空,则直接返回false
2.工作线程数达到或超过最大容量,或者如果是添加核心线程时数量线程达到最大容量或者添加max线程达到最大容量,直接返回false,否则线程数加1,并且跳出自旋
![](https://img.haomeiwen.com/i18159984/1ed9760a27fb8e91.png)
1.new一个Worker对象(该对象是整个线程池的核心,来判断到底是新开一个线程还是复用原来的线程)
2.拿到对应的线程,再判断一下线程池是否被关闭,或者正在关闭并且任务为null。然后加入到workers里面。
我们再来看一下Worker对象。
![](https://img.haomeiwen.com/i18159984/0e49ce3b114b2723.png)
可以看到Worker是可以内部类,并且继承了AQS,实现了Runnable接口,我们就直接来看一下他的run方法
![](https://img.haomeiwen.com/i18159984/9be66d8ef59b2d08.png)
![](https://img.haomeiwen.com/i18159984/4578f216b2ebd5a2.png)
1.调用一下封装的unlock方法,将锁打开,可以运行时中断
2.如果任务不为空,或者列表中的任务不为空,就锁一下,然后判断一下线程是否正在停止,如果是的话,就中断线程
3.在run方法前执行一段beforeExecute方法,可以实现这个方法,然后执行run方法。
至于线程如何复用的,是如下代码
![](https://img.haomeiwen.com/i18159984/4def2208dfceb049.png)
1.自旋,如果线程池要关闭或者队列是空的,就减少线程数量
2.判断一下是否允许核心线程数超时,或者当前的活跃线程数是否大于核心线程数
3.如果活跃线程数大于最大线程数,或者超时了,并且活跃线程数大于1或者队列为空。然后就减少线程数。
4.如果timed是ture的话,就返回队列头部的任务,如果队列为空就返回null,如果timed是false的话,也返回队列头部的任务,如果队列为空的话就阻塞。这种阻塞操作使得线程不干活时不会被销毁,从而线程复用
网友评论