前文回顾
接着上一篇文章,知道线程池的一些相关概念后,一起来看看实现原理吧。
本文讲述ThreadPoolExecutor源码,力求理清执行顺序,尽量保持思路清晰,请耐心看完~
文章导读
- 内部类-Worker(基本属性,构造方法,AQS相关钩子方法,线程中断方法)
- 提交任务(execute,addWorker)
- 执行任务(runWorker)
- 关闭方法(tryTerminated,shutdown,shutdownNow)
一、内部类-Worker
Worker表示线程池中的每一个任务,与线程一一对应。是AQS的子类,实现其独占模式,封装一些了对于资源操作的方法。
1.1 基本属性
重要的是thread(当前worker线程),firstTask(初始任务),completedTasks(任务计数器)。
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* 这个类永远不会被序列化,设置serialVersionUID
* 是为了停止javac编译器的警告
*/
private static final long serialVersionUID = 6138294804551838833L;
//表示一个工作线程,null则说明线程工厂创建出错了
final Thread thread;
//需要运行的初始任务,可能为空
Runnable firstTask;
//每个线程的任务计数器,表示完成的任务数量
volatile long completedTasks;
......
}
1.2 构造方法
Worker在第一次接收任务的时候被线程工厂创建,其中成员变量thread就是基于Worker的线程。
Worker(Runnable firstTask) {
//设置AQS.state为-1表示在运行之前禁止被中断
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
1.3 对AQS相关方法的实现
Worker既然继承了AbstractQueuedSynchronizer,就一定会有相关钩子方法的实现。钩子方法是isHeldExclusively(),tryAcquire(int unused),tryRelease(int unused)。而lock(),tryLock(),unlock(),isLocked()都是对他们的进一步封装,非常的简练。如果有兴趣可以回忆回忆ReentrantLock都是怎么实现的,比较一下区别。
state表示当前线程的运行状态,总共有3种情况:
- -1,表示在运行之前禁止被中断。
- 0,表示锁没有被任何线程获取。
- 1,表示锁已经被占有。
//是否持有独占锁,根据state判断
//state 0:表示锁没有被任何线程获取
//state 1:表示锁已经被占有
protected boolean isHeldExclusively() {
return getState() != 0;
}
//尝试获取锁,成功后设置当前线程为锁的持有者
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//释放锁
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
//会先调用tryAcquire(1),若拿不到锁则阻塞获取锁资源
public void lock() { acquire(1); }
//尝试获取锁,不会阻塞
public boolean tryLock() { return tryAcquire(1); }
//会先调用tryRelease(1),若释放成功则去等待队列从队尾向前找下一个需要唤醒的节点
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
1.4 对线程的中断方法
interruptIfStarted():用于中断工作线程,保证要中断的thread必须是已经初始化完成的,而且已经运行了。需要注意的是,Worker的构造方法中将state设置为-1。
void interruptIfStarted() {
Thread t;
//确保线程已经运行并且中断标志为还是false时,就执