乍一看,addWorker(Runnable, boolean)方法还蛮长的,这里,我们还是将addWorker(Runnable, boolean)方法进行拆解 。
(1)检查任务队列是否在某些特定的条件下为空,代码如下所示 。
// 检查队列是否在某些特定的条件下为空if (rs >= SHUTDOWN &&! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))return false;(2)在通过步骤(1)的校验后,则进入内层for循环,在内层for循环中通过CAS来增加线程池中的线程数量,如果CAS操作成功,则直接退出双重for循环 。如果CAS操作失败,则查看当前线程池的状态是否发生了变化,如果线程池的状态发生了变化,则通过continue关键字重新通过外层for循环校验任务队列,检验通过再次执行内层for循环的CAS操作 。如果线程池的状态没有发生变化,此时上一次CAS操作失败了,则继续尝试CAS操作 。代码如下所示 。
for (;;) {//获取线程池中的线程数量int wc = workerCountOf(c);//如果线程池中的线程数量超出限制,直接返回falseif (wc >= CAPACITY ||wc >= (core ? corePoolSize : maximumPoolSize))return false;//通过CAS方式向线程池新增线程数量if (compareAndIncrementWorkerCount(c))//通过CAS方式保证只有一个线程执行成功,跳出最外层循环break retry;//重新获取ctl的值c = ctl.get();//如果CAS操作失败了,则需要在内循环中重新尝试通过CAS新增线程数量if (runStateOf(c) != rs)continue retry;}(3)CAS操作成功后,表示向线程池中成功添加了工作线程,此时,还没有线程去执行任务 。使用全局的独占锁mainLock来将新增的工作线程Worker对象安全的添加到workers中 。
总体逻辑就是:创建新的Worker对象,并获取Worker对象中的执行线程,如果线程不为空,则获取独占锁,获取锁成功后,再次检查线线程的状态,这是避免在获取独占锁之前其他线程修改了线程池的状态,或者关闭了线程池 。如果线程池关闭,则需要释放锁 。否则将新增加的线程添加到工作集合中,释放锁并启动线程执行任务 。将是否启动线程的标识设置为true 。最后,判断线程是否启动,如果没有启动,则调用addWorkerFailed(Worker)方法 。最终返回线程是否起送的标识 。
//跳出最外层for循环,说明通过CAS新增线程数量成功//此时创建新的工作线程boolean workerStarted = false;boolean workerAdded = false;Worker w = null;try {//将执行的任务封装成workerw = new Worker(firstTask);final Thread t = w.thread;if (t != null) {//独占锁,保证操作workers时的同步final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//此处需要重新检查线程池状态//原因是在获得锁之前可能其他的线程改变了线程池的状态int rs = runStateOf(ctl.get());if (rs < SHUTDOWN ||(rs == SHUTDOWN && firstTask == null)) {if (t.isAlive())throw new IllegalThreadStateException();//向worker中添加新任务workers.add(w);int s = workers.size();if (s > largestPoolSize)largestPoolSize = s;//将是否添加了新任务的标识设置为trueworkerAdded = true;}} finally {//释放独占锁mainLock.unlock();}//添加新任成功,则启动线程执行任务if (workerAdded) {t.start();//将任务是否已经启动的标识设置为trueworkerStarted = true;}}} finally {//如果任务未启动或启动失败,则调用addWorkerFailed(Worker)方法if (! workerStarted)addWorkerFailed(w);}//返回是否启动任务的标识return workerStarted;addWorkerFailed(Worker)方法在addWorker(Runnable, boolean)方法中,如果添加工作线程失败或者工作线程启动失败时,则会调用addWorkerFailed(Worker)方法,下面我们就来看看addWorkerFailed(Worker)方法的实现,如下所示 。
private void addWorkerFailed(Worker w) {//获取独占锁final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//如果Worker任务不为空if (w != null)//将任务从workers集合中移除workers.remove(w);//通过CAS将任务数量减1decrementWorkerCount();tryTerminate();} finally {//释放锁mainLock.unlock();}}
经验总结扩展阅读
- 手机的信号是通过卫星接收的吗
- 和家亲怎么把别人禁用
- 如何通过手机远程控制他人手机呢
- 【Python+C#】手把手搭建基于Hugging Face模型的离线翻译系统,并通过C#代码进行访问
- 如何提高载波采集成功率
- 如何鉴别镜头是新的
- 如何通过 Java 代码隐藏 Word 文档中的指定段落
- day44-反射03
- 漂洗是什么意思
- 怎样让圆脸变瓜子脸?