线程池的使用范围实在是太广了,很多组件的底层使用线程池创建、管理线程。之前有一篇关于线程池使用,增强的文章:GYM4-线程池
重要属性
1 |
|
execute操作
Executor接口定义的方法,执行提交的任务。执行任务的具体线程可能是新创建的也可能是已经存在的。如果线程池关闭或者容量达到上限,RejectedExecutionHandler持有拒绝策略。
任务提交分为三个步骤:
1.正在运行的线程数量小于corePoolSize,尝试创建一个新的线程执行当前任务。调用addWorker方法,它会使用原子操作检查runState和workerCount。当无法执行提交任务时,返回false。
2.如果成功的入队,我们仍然需要检查我们可以让它入队(因为存在最后一个线程结束的可能),或者进入这个方法时线程池关闭。
3.如果进入任务队列失败,我们尝试创建一个新的线程。如果失败,一定是线程池是关闭或者饱和。
1 |
|
addWroker操作
根据当前线程池的装填和给定的边界(核心、最大线程数)检查时候能够创建新的工作线程。如果创建成功调整工作线程的数量,创建一个新的线程运行当前任务。因为线程池关闭或者正在关闭导致的线程创建失败返回false。不管是因为线程工厂返回null还是因为异常(典型是线程启动时的OutOfMemoryError),我们都要回滚。
java中的标签:
- break lable 跳转到标签所在的循环,并且跳过循环
- continue lable 跳转到标签所在的循环,并且继续执行循环
1 |
|
Worker子类
持有运行任务的线程。继承自AbstractQueuedSynchronizer,实现了非重入的锁,保证工作线程的线程安全。参考AbstractQueuedSynchronizer解析(1)
同时Worker实现Runnable接口,也就是说他会作为一个任务被执行,而执行这个任务的线程就是Woker自身包含的Thread字段。
1 |
|
runWoker方法
工作线程不断从队列中获取任务并且执行他们,下面是对应的几个问题:
1.一开始执行firstTask,之后从阻塞队列中获取。如果获得的任务为null说明线程池状态或者参数发生改变,当前工作者应该被清理。
2.任务执行前持有锁是为了阻止其他线程中断正在执行的任务,除非线程器停止,线程不会被中断。
3.调用beforeExecute可能产生异常,这种情况下我们会杀死线程而不是继续执行任务。
4.如果任务报错,我们执行afterExecute方法。
5.afterExecute方法异常,线程被杀死。
1 |
|