本篇文章主要分析线程池的设计思路
什么是线程池
线程池是一种池化技术,通过创建多个线程存储到容器中,有任务时取出线程来处理,处理完之后继续等待执行其他任务,通过重复利用线程来减少线程的创建和上下文切换带来的开销,提升程序的执行效率。
为什么用线程池
现在的系统越来越复杂,业务也越来越多,高并发场景也越来越普遍,当需要处理大量任务时就不可避免地要创建线程来异步执行,但是如果每个任务都要创建新的线程来执行,就需要更多的CPU和内存资源,甚至会出现OOM的情况,所以通过使用线程池技术,可以有效降低资源的消耗。
怎么实现复用线程的
当一个线程处理完任务后,并没有把它销毁,而是通过继续等待来实现处理多个任务的目的。
线程池存储多少线程
因为线程池的目的就是要减少线程的数量,所以线程池中线程数不能太大,要根据实际业务需要和压测情况设置一个合理的大小,所以需要一个最大线程数量maximumPoolSize
一开始就把线程创建完吗
本着尽可能用更少的线程去处理更多任务的原则,可以设置一个最少要创建的线程数量(核心线程数)corePoolSize,小于这个数量时,只要没有空闲线程了就创建新线程去处理任务。
线程数量达到核心线程数怎么办
- 一种方式:继续创建线程去处理新任务;
- 另一种方式:让新任务先等着,等有空闲线程了再来处理。
第一种方式不管什么情况下都要去创建线程,就需要更多的资源;当核心线程处理的任务耗时较短时,很快就会有线程空闲出来,所以采用第二种方式创建一个阻塞队列BlockingQueue,线程数量达到corePoolSize就让任务先进入阻塞队列等着,有线程空闲了就去队列中取出任务来处理。
阻塞队列要多大
如果任务无限多,都存到队列中就会造成OOM,所以可以给队列设置一个大小,超过这个数量的就不再存了。
阻塞队列满了又怎么办
如果阻塞队列满了说明正在处理的任务比较耗时,或者短时间来了大量任务,核心线程已经处理不过来了,这时就只能继续创建线程来处理任务。
任务处理完线程空闲了怎么办
超出核心线程数量的线程如果空闲了可以销毁掉,避免大量线程都空闲等待占用资源。但是如果立刻销毁掉,马上又来了大量新任务就不得不继续创建线程来处理,所以可以给非核心线程设置一个等待时间keepAliveTime,空闲之后超过等待时间,如果还没有新任务就销毁掉。
线程数量达到最大怎么办
创建的线程数量达到了设置的最大值,新进来的任务不管是直接丢弃还是创建新线程来处理,或者其他什么方式,可能都不是用户想要的结果,所以可以预设几种策略RejectedExecutionHandler供用户选择,把决定权交给用户,让用户来决定采用什么策略,如果都不满足的话也可以让用户自定义策略。
总结
- 创建线程处理任务,直到线程数量达到
corePoolSize - 核心线程满了,新任务进入阻塞队列等待
- 阻塞队列满了,继续创建新线程处理任务
- 线程数达到最大值
maximumPoolSize,执行拒绝策略 - 空闲线程等待时间超过
keepAliveTime,销毁线程,保留corePoolSize数量的线程