变量ctl实现原理:
ThreadPoolExecutor中使用变量ctl来描述线程池状态,存储的是当前线程池的运行状态和线程池中的线程总数,相关代码如下:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//数值为29,用于区分线程池状态区和线程池总数区
private static final int COUNT_BITS = Integer.SIZE - 3;
//用于底层二进制运算的中间变量,为00011111111111111111111111111111,后面29个1.
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 线程池状态,使用位移运算
//-1左移29位,最后二进制为11100000000000000000000000000000,后面29个0
private static final int RUNNING = -1 << COUNT_BITS;
//0左移29位,最后二进制为00000000000000000000000000000000,后面29个0
private static final int SHUTDOWN = 0 << COUNT_BITS;
//1左移29位,最后二进制为00100000000000000000000000000000,后面29个0
private static final int STOP = 1 << COUNT_BITS;
//2左移29位,最后二进制为00200000000000000000000000000000,后面29个0
private static final int TIDYING = 2 << COUNT_BITS;
//3左移29位,最后二进制为00300000000000000000000000000000,后面29个0
private static final int TERMINATED = 3 << COUNT_BITS;
// 获取线程池状态,将ctl的后29位变成0
private static int runStateOf(int c) { return c & ~CAPACITY; }
//获取线程总数,将ctl前3位转换成0
private static int workerCountOf(int c) { return c & CAPACITY; }
//初始化ctl,将线程池状态和线程总数使用或运算合并到一个整型数据中。
private static int ctlOf(int rs, int wc) { return rs | wc; }
ThreadPool一共定义了5种线程池状态,各状态含义如下:
状态 | 解释 |
---|---|
RUNNING | 运行态,可处理新任务并执行队列中的任务 |
SHUTDOW | 关闭态,不接受新任务,但处理队列中的任务 |
STOP | 停止态,不接受新任务,不处理队列中任务,且打断运行中任务 |
TIDYING | 整理态,所有任务已经结束,workerCount = 0 ,将执行terminated()方法 |
TERMINATED | 结束态,terminated() 方法已完成 |
当调用shutdown()方法时,线程池进入SHUTDOW状态, 当调用shutdownNow()方法时,线程池进入STOP状态。
ctl是一个整型数据,一共占32位。因为线程池一共只有5种状态,可以使用一个3位的二进制数表示,所以使用高位的3位表示线程池状态,剩下29位用来表示线程的个数。在代码中涉及了底层二进制数的运算。线程池状态二进制表示如下:
整个ctl的状态,会在线程池的不同运行阶段进行CAS转换。
核心内部类Worker
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
//worker对应的自己的线程
final Thread thread;
//该线程第一个任务
Runnable firstTask;
//运行的总任务数
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
Worker是一个Runnable,同时拥有一个thread,这个thread就是要开启的线程,,在新建Worker对象时会同时新建一个Thread对象,同时将Worker自己作为参数传入TThread,这样当Thread的start()方法调用时,运行的实际上是Worker的run()方法,run()方法就会调用ThreadPoolExecutor类的runWorker方法。 在线程池中,开启一共新线程,就是创建一个新的Worker,然后调用内部thread的start()方法 runWorker方法简化后如下:
final void runWorker(Worker w) {
Runnable task = w.firstTask;
w.firstTask = null;
while (task != null || (task = getTask()) != null){
task.run();
}
runWorker方法会一直调用getTask()方法来获取要执行的任务。getTask()方法简化如下:
private Runnable getTask() {
if(一些特殊情况) {
return null;
}
Runnable r = workQueue.take();
return r;
getTask()就是从WorkQuene中获取还未执行的任务。因为BlockingQueue是个阻塞队列,BlockingQueue.take()得到如果是空,则进入等待状态直到BlockingQueue有新的对象被加入时唤醒阻塞的线程。所以一般情况Thread的run()方法就不会结束,而是不断执行从workQueue里的Runnable任务。
execute执行流程:
public void execute(Runnable command) {
if (command == null) // 命令为null,抛出异常
throw new NullPointerException();
// 获取线程池控制状态
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { // worker数量小于corePoolSize
if (addWorker(command, true)) // 添加worker
// 成功则返回
return;
// 不成功则再次获取线程池控制状态
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { // 线程池处于RUNNING状态,将命令(用户自定义的Runnable对象)添加进workQueue队列
// 再次检查,获取线程池控制状态
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command)) // 线程池不处于RUNNING状态,将命令从workQueue队列中移除
// 拒绝执行命令
reject(command);
else if (workerCountOf(recheck) == 0) // worker数量等于0
// 这里百度是添加idle线程,对这部分还不理解
addWorker(null, false);
}
else if (!addWorker(command, false)) // 添加worker失败
// 拒绝执行命令
reject(command);
}
addWorker方法简化如下:
private boolean addWorker(Runnable firstTask, boolean core) {
int wc = workerCountOf(c);
if (wc >= (core ? corePoolSize : maximumPoolSize)) {
return false;
}
w = new Worker(firstTask);
final Thread t = w.thread;
t.start();
}
所以线程池添加任务过程可以用下图表示: submit()方法底层还是调用的execute方法。如果添加失败,会启动拒绝策略处理任务。
参考资料:https://blog.csdn.net/yjw123456/article/details/77719061