一:执行流程:
任务先进入corePool(核心线程池)
如果corePool满了,进入阻塞队列中
如果阻塞队列也满了,进入maxminPool非核心线程池(maxminPool中创建的线程执行完任务后经过一段时间会被垃圾回收机制回收,下次还需要重新创建线程执行任务)
如果非核心线程池也满了,则reject
为什么先进入阻塞队列再进入非核心线程池?
因为任务到非核心线程池需要创建线程执行任务,需要消耗资源,而核心线程池(corePool)内的线程短时间不会被回收,手头任务完成后继续从阻塞队列中拿任务做,不需要消耗创建线程等资源。
二:ThreadPoolExecutor中的垃圾回收
未使用shutdown方法
工作线程的数量减少到核心线程数大小(即回收非核心线程)
判断条件:keepAliveTime
调用shutdown等方法
无论是核心还是非核心,所有工作线程都会被销毁
三:JDK中常用线程池
newSingleThreadExecutor
参数
corePoolSize=1
maximumPoolSize=1
keepAliveTime+TimeUnit=0s
BlockingQueue=LinkedBlockingQueue
相当于是创业型公司,什么活都是自己在干
newCachedThreadPool
参数
corePoolSize=0
maximumPoolSize=max
keepAliveTime+TimeUnit=60s
BlockingQueue=SynchronousQueue 相当于大小为0
相当于是外包公司,没有核心人员,有活就招人来干,缺点是线程没有得到复用
newFixedThreadPool
参数
corePoolSize=nThreads (自己定义)
maximumPoolSize=nThreads
keepAliveTime+TimeUnit=0s
BlockingQueue=LinkedBlockingQueue
相当于是国企,有一定的核心人员,任务太多就排队等着
四:ThreadPoolExecutor工作中的问题
线程池的参数不好配置
五:动态线程池
动态线程池的主要思想是封装了ThreadPoolExecutor类的setCorePoolSize等方法,在运行期,线程池使用方调用此方法设置corePoolSize之后,线程池会直接覆盖原来的corePoolSize值。
首先通过对线程池的监控,如果线程池的使用超过了80%左右,通过钉钉等平台通知授权的开发人员来动态修改线程池参数。
在实际应用中我们获取并发性的场景主要是两种:(1)并行执行子任务,提高响应速度。这种情况下,应该使用同步队列,没有什么任务应该被缓存下来,而是应该立即执行。(2)并行执行大批次任务,提升吞吐量。这种情况下,应该使用有界队列,使用队列去缓冲大批量的任务,队列容量必须声明,防止任务无限制堆积。
六:线程池的五个状态
1. RUNNING:线程池正常运⾏中,可以正常的接受并处理任务 2. SHUTDOWN:线程池关闭了,不能接受新任务,但是线程池会把阻塞队列中的剩余任务执⾏完,剩 余任务都处理完之后,会中断所有⼯作线程 3. STOP:线程池停⽌了,不能接受新任务,并且也不会处理阻塞队列中的任务,会中断所有⼯作线程 4. TIDYING:当前线程池中没有⼯作线程后,也就是线程池没有⼯作线程在运⾏了,就会进入 TIDYING,这个状态是⾃动发⽣在SHUTDOWN和STOP之后的 5. TERMINATED:线程池处于TIDYING状态后,会执⾏terminated()⽅法,执⾏完后就会进⼊ TERMINATED状态,在ThreadPoolExecutor中terminated()是⼀个空⽅法,可以⾃定义线程池重写 这个⽅法