publicvoidexecute(Runnable command){ // 为null的话报空指针异常 if (command == null) thrownew NullPointerException(); /* * Proceed in 3 steps: * * 1. 如果当前运行的线程数少于corePoolSize, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. 如果任务被成功加入进阻塞队列, then we still need * to 二次检查 whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ // clt记录runState和workerCount int c = ctl.get(); /* * workerCountOf方法取出低29位的值,表示当前活动的线程数; * 如果当前活动线程数小于corePoolSize,则新建一个线程放入线程池中; * 并把任务添加到该线程中。 */ if (workerCountOf(c) < corePoolSize) { /* * addWorker中的第二个参数表示限制添加线程的数量的判断依据; * 如果为true,根据corePoolSize来判断; * 如果为false,则根据maximumPoolSize来判断 */ if (addWorker(command, true)) return; // 如果添加失败,则重新获取ctl值 c = ctl.get(); } // 如果当前线程池是运行状态并且任务添加到队列成功 if (isRunning(c) && workQueue.offer(command)) { // 源码注释提到的二次检查 int recheck = ctl.get(); /* * 再次判断线程池的运行状态,如果不是运行状态 * 由于之前已经把command添加到workQueue中了,这时需要移除该command * 执行过后通过handler使用拒绝策略对该任务进行处理,整个方法返回 */ if (! isRunning(recheck) && remove(command)) reject(command); /* * 获取线程池中的有效线程数,如果数量是0,则执行addWorker方法 * 这里传入的参数表示: * 1. 第一个参数为null,表示在线程池中创建一个线程,但不去启动; * 2. 第二个参数为false,将线程池的有限线程数量的上限设置为maximumPoolSize,添加线程时根据maximumPoolSize来判断; * 如果判断workerCount大于0,则直接返回,在workQueue中新增的command会在将来的某个时刻被执行。 */ elseif (workerCountOf(recheck) == 0) addWorker(null, false); } /* * 如果执行到这里,有两种情况: * 1. 线程池已经不是RUNNING状态; * 2. 线程池是RUNNING状态,但workerCount >= corePoolSize并且workQueue已满。 * 这时,再次调用addWorker方法,但第二个参数传入为false,将线程池的有限线程数量的上限设置为maximumPoolSize; * 如果失败则拒绝该任务 */ elseif (!addWorker(command, false)) reject(command); }