addWorker可以分为两部分:判断当前是否满足创建新工作线程的条件、创建并启动新的Worker工作线程 。
判断当前是否满足创建新工作线程的条件入口处开始的retry标识的for循环部分,便是用于判断是否满足创建新工作线程的条件 。
- 首先判断当前工作线程数量是否超过了理论的最大值CAPACITY(即2^29-1),超过了则不能创建,返回false,不创建新工作线程
- 根据boolean类型参数core判断是否创建核心工作线程,core=true则判断是否超过了corePoolSize的限制,core=false则判断是否超过了maximumPoolSize的限制 。不满足则返回false,不创建新工作线程
- 满足上述限制条件后,则说明可以创建新线程了,compareAndIncrementWorkerCount方法进行cas的增加当前工作线程数 。如果cas失败,则说明存在并发的更新了,则再一次的循环重试,并再次的进行上述检查 。
创建并启动新的Worker工作线程在通过retry那部分的层层条件检查后,紧接着便是实际创建新工作线程的逻辑 。
- 首先通过Worker的构造方法创建一个新的Worker对象,并将用户提交的任务作为firstTask参数传入 。
- 判断Worker在构造时线程工厂是否正确的生成了一个Thread(判空),如果thread == null的话直接返回false,标识创建新工作线程失败 。
- 在mainLock的保护下,将新创建的worker线程加入workers集合中
- 启动Worker中的线程(myWorkerThread.start()),启动后会执行Worker类中的run方法,新的工作线程会执行runWorker方法(下文会展开分析runWorker)
- 如果Worker中的线程不是alive状态等原因导致工作线程启动失败,则在finally中通过addWorkerFailed进行一系列的回滚操作
addWorkerFailed(addWorker的逆向回滚操作)addWorker中工作线程可能会启动失败,所以要对addWorker中对workers集合以及workerCount等数据的操作进行回滚 。
/*** 当创建worker出现异常失败时,对之前的操作进行回滚* 1 如果新创建的worker加入了workers集合,将其移除* 2 减少记录存活的worker个数(cas更新)* 3 检查线程池是否满足中止的状态,防止这个存活的worker线程阻止线程池的中止(v1版本不考虑,省略了tryTerminate)*/private void addWorkerFailed(MyWorker myWorker) {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {if (myWorker != null) {// 如果新创建的worker加入了workers集合,将其移除workers.remove(myWorker);}// 减少存活的worker个数decrementWorkerCount();// 尝试着将当前worker线程终止(addWorkerFailed由工作线程自己调用)// tryTerminate();} finally {mainLock.unlock();}}
runWorker(工作线程核心执行逻辑)前面介绍了用户如何向线程池提交任务,以及如何创建新工作线程Worker,下面介绍工作线程在线程池中是如何运行的 。
经验总结扩展阅读
- 如何保护环境
- 哥哥给弟弟的生日祝福句子
- 送给自己的生日快乐句子
- 闺蜜生日快乐的祝福语
- 哪些星座善于伪装自己 不会轻易透露隐私
- 廉租房能自己装修吗 廉租房申请下来可以不住吗
- 申请廉租房需要查自己的个人征信吗 公租房与廉租房的区别在哪里
- 廉租房需要摇号吗 廉租房需要自己装修吗
- 自己手剥核桃仁怎么储存
- 我的Vue之旅 10 Gin重写后端、实现页面详情页 Mysql + Golang + Gin