一、简介
ThreadPoolExecutor是Java中的一个类,它实现了ExecutorService接口,用于创建一个线程池。线程池是一种线程使用模式,它维护着一组线程,等待监督管理者分配可以并发执行的任务。ThreadPoolExecutor的主要目标是减少在创建和销毁线程上花费的时间以及系统资源的开销,提高系统的响应速度。
二、工作原理
- 当一个任务通过execute(Runnable)方法添加到线程池时,如果线程池中的线程数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也会创建新的线程来处理被添加的任务。
- 如果线程池中的线程数量等于corePoolSize,但缓冲队列workQueue未满,那么任务会被放入缓冲队列等待执行。
- 如果线程池中的线程数量大于corePoolSize,缓冲队列workQueue已满,并且线程池中的线程数量小于maximumPoolSize,那么会创建新的线程来处理被添加的任务。
- 如果线程池中的线程数量大于corePoolSize,缓冲队列workQueue已满,并且线程池中的线程数量等于maximumPoolSize,那么会通过handler所指定的策略来处理此任务。
public void execute(Runnable command) {if (command == null)throw new NullPointerException();//获取ctl的值int c = ctl.get();/*** 第一步:* 调用workerCountOf 计算活跃的工作线程数* 判断工作线程数 是否小于 核心线程数*/if (workerCountOf(c) < corePoolSize) {// 工作线程数 小于 核心线程数,则通过addWorker方法创建核心线程,true代表核心线程if (addWorker(command, true))// 此时线程被创建,但是需要等调用start();线程被启动了,才算addWorker成功return;//创建新的线程后,ctl被修改,这里重新获取ctl属性值,因为当有多个线程同时调用addWorker,只有一个线程会成功创建新的线程后修改ctl,此时其他的线程需要重新获取ctl属性值c = ctl.get();}/*** 第二步:* 工作线程数 不小于 核心线程数,且当线程池处于RUNNING状态时* 尝试将任务加入到队列中** isRunning(c) 判断线程池状态,创建线程失败可能造成线程池停止,所以需要再次判断线程池运行状态*/if (isRunning(c) && workQueue.offer(command)) {// 添加任务到队列成功后,再次获取最新ctl属性值int recheck = ctl.get();// 加入队列后这里又重新调用了isRunning(recheck) ,主要是防止任务加入队列后,线程池状态改变了//如果线程池不是RUNNING状态时,就需要移除已加入队列的任务(线程池不是RUNNING状态,比如调用了 shutdown 方法等,无法执行)if (! isRunning(recheck) && remove(command))// 如果线程池不是RUNNING状态,并且移除任务成功,则执行拒绝策略reject(command);// 走到这里说明,线程池不是处于RUNNING状态// 调用workerCountOf(recheck) 获取活跃的工作线程,判断是否为0,如果为0,则创建非核心线程将队列中任务执行完else if (workerCountOf(recheck) == 0)// 如果工作线程为0,则创建一个空的任务,通过addWorker方法的t.start启动线程,然后通过runWorker方法执行task.run(),直到队列中所有的任务都执行完成addWorker(null, false);}/*** 第三步:* 如果队列满了,则创建非核心线程,false代表非核心线程*/else if (!addWorker(command, false))// 核心线程数 + 非核心线程数 超过了最大线程数,则执行拒绝策略reject(command);}