线程池添加过程详见(线程池相关);
其中一个核心类为 Worker,继承 AbstractQueuedSynchronizer,实现了 Runnable
1、线程池生命周期各状态
RUNNING: 接收新任务,也处理队列任务
SHUTDOWN: 不接收新任务,但是处理队列任务
STOP: 不接收新任务,不处理队列任务并且中断正在进行的任务
TIDYING: 所有任务都终止,workerCount为零,线程状态转为TIDYING,将运行terminated()方法
TERMINATED: terminated() 方法执行完毕
2、内部相关状态
AtomicInteger类型的ctl变量,高3位标识线程池的运行状态,低29(COUNT_BITS)位标识线程池中的线程数;
1、RUNNING:-1 << COUNT_BITS,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
2、SHUTDOWN: 0 << COUNT_BITS,即高3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
3、STOP : 1 << COUNT_BITS,即高3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;
4、TIDYING : 2 << COUNT_BITS,即高3位为010, 所有的任务都已经终止;
5、TERMINATED: 3 << COUNT_BITS,即高3位为011, terminated()方法已经执行完成
6、CAPACITY:(1 <<29-1)=536870912 -1 = 536870911
3、任务的执行
执行方法链如下:
execute(Runnable command) –> addWorker(Runnable firstTask,boolean core) –>runWorker(Worker w)。
线程池的工作线程由Worker类实现,通过ReentrantLock锁,把worker实例插入到HashSet中,并启动Worker中的线程。
而Worker类的构造方法实现可以看出:threadFactory创建线程thread时,将worker实例本身this作为参数传入,执行start()时,本质是调用Worker的run()方法,run() 又调用了外部的runWorker()方法。
firstTask执行完成之后,通过getTask方法从阻塞队列中获取等待的任务,如果队列中没有任务,getTask方法会被阻塞并挂起,不会占用cpu资源
3.1 execute(Runnable command) 执行过程
为什么需要double check线程池的状态?
在多线程环境下,线程池的状态时刻在变化,而ctl.get()是非原子操作,很有可能刚获取了线程池状态后线程池状态就改变了。判断是否将command加入workque是线程池之前的状态。倘若没有double check,万一线程池处于非running状态(在多线程环境下很有可能发生),那么command永远不会执行。
3.2 addWorker(Runnable firstTask,boolean core)
主要分为两步
第一步 采用CAS更新线程池数量
第二步 新建线程,成功添加到hashSet后启动新线程
3.3 runWorker(Worker w)
因Woker实现了 Runnable接口,调用woker的start方法时,其实是执行了run(),而Worker的run()实际调用外部的 runWorker(Worker w);
1、线程启动,先释放锁,设置AQS的state为0,表示运行可中断
2、执行firsTask任务或者从阻塞队列workerQueue中获取任务
3、执行加锁(最后有解锁流程)
4、判断线程池状态,如果是STOP,当前线程赢立即中断
5、执行beforeExecute(),执行任务run方法,执行afterExecute()方法
6、释放锁
4、其他
Q. 线程池是什么时候创建线程的?
A.任务提交的时候
Q.任务runnable task是先放到core到maxThread之间的线程,还是先放到队列?
A.先放队列!!!
Q. 队列中的任务是什么时候取出来的?
A. worker中 runWorker() 一个任务完成后,会取下一个任务
Q. 什么时候会触发reject策略?
A.队列满并且maxthread也满了, 还有新任务,默认策略是reject
Q. core到maxThread之间的线程什么时候会die?
A. 没有任务时,或者抛异常时。
core线程也会die的,core到maxThread之间的线程有可能会晋升到core线程区间,
core max只是个计数,线程并不是创建后就固定在一个区间了
Q. task抛出异常,线程池中这个work thread还能运行其他任务吗?
A. 不能。 但是会创建新的线程, 新线程可以运行其他task。
对于 schedulerThreadPoolExecutor? 虽然有新线程,但是旧的循环任务不会再继续执行了, 开发实践推荐任务中捕获所有Exception
参考:
Java线程池实现原理与源码解析(jdk1.8)
线程池ThreadPoolExecutor分析: 线程池是什么时候创建线程的,队列中的任务是什么时候取出来的?