10分钟了解线程池,阿里再也不担心我线程池资源耗尽了
线程池:避免了创建线程和销毁线程的资源损耗。
Executors提供四种线程池:
newCachedThreadPool :缓存线程池,如果线程池长度超过处理需要,可回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool :定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool :计划线程池,支持定时及周期性任务执行。
newSingleThreadExecutor :单线程线程池,用唯一的线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
先了解下线程池必备的以下几个属性:
poolSize : 当前程序运行的线程数。
coreSize: 核心线程数。
MaximumPoolSize: 线程池中最大线程数。
keepAliveTime:线程空闲时间超过,则会超时退出。
BlockingQueue :设置一个阻塞用来存放将要执行的等待任务。
(线程安全:保证取队列元素时一个只能取一个,且头元素没有时不能取,满时不能加入)
线程池的运行流程:
当需要执行一个任务时:
poolsize < coresize ->开启一个新的线程执行
poolsize = coresize && 队列未满 -> 这时已经达到了核心线程数,线程不够了,加入到阻塞队列中,慢慢执行。
Poolsize < MaximumPoolSize && 队列已满 -> 这时队列都满了,那不行啊 ,快爆了,在开启一个新线程吧。
(通常超出核心线程的线程是“借”的,也就是说超出核心线程的情况算是一种能够预见的异常情况,并且这种情况并不常常发生(如果常常发生,那我想你应该调整你的核心线程数了)
Poolsize = MaximumPoolSize && 队列满了 -> 已经所有办法用尽了,会根据饱和策略RejectedExecutionHandler拒绝新的任务。
(如果设置了keepAliveTime,可以通过以下配置来确定小于corePoolSize时,是否启动超时处理。
但是对于超出MaximumPoolSize,一定会进行超时处理,因为这些线程本就不是正常情况。
allowCoreThreadTimeOut:是否允许核心线程超时退出。
如果该值为false(默认),且poolSize<=corePoolSize,线程池都会保证这些核心线程处于存活状态,不会超时退出。(所以只要不是超过corePoolSize,线程都会空闲而不是销毁)
如果为true,则不论poolSize的大小,都允许超时退出。
如果poolSize>corePoolSize,则该参数不论true还是false,都允许超时退出。
)
下面就看看创建线程的源码:
自定义线程池:
固定大小线程池:
单个线程池:
缓存线程池:
定时线程池:
线程池拒绝策略:
当线程池满了,队列也满了,这时候需要执行拒绝策略。默认策略感觉不太好,如果一满就会报异常停止运行。
AbortPolicy(默认)
默认策略,直接跑出异常阻止系统正常运行
CallerRunsPolicy
“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将任务回馈至调用方,比如main线程
DiscardOldestPolicy
抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
DiscardPolicy
直接丢弃任务,不给予任何处理也不跑出异常,如果允许任务丢失