线程池执行器ThreadPoolExecutor源码完整解读
1 前言
ThreadPoolExecutor
的基本概念和用法已经在之前的文章线程池ThreadPoolExecutor简介 、Executor框架完整解读中做过详细的说明,这里主要基于JDK1.8对ThreadPoolExecutor
从源码级别分析其实现原理。
ThreadPoolExecutor
是ExecutorService
的最重要的实现类,ThreadPoolExecutor
不直接实现ExecutorService
接口,它直接继承于AbstractExecutorService
抽象类(AbstractExecutorService的源码实现在AbstractExecutorService源码完全解析已做过分析。), AbstractExecutorService
对ExecutorSerivice
接口中的一些方法做过的默认实现 。
线程池有两个重要的概念一个是任务队列,另一个是工作者线程 。
任务队列是存放任务的容器,工作者线程会依次不断地到队列中获取任务并执行。
2 重要的成员内部类Worker
Worker
继承于AbstractQueuedSynchronizer
抽象类,它又实现了Runnable
接口。
Worker可以理解为一个工作者线程,但内部属性又不只有一个Thread属性,除此之外还有首任务firstTask、线程所完成的任务数completedTasks。
Worker
类主要是维护执行任务的线程的中断状态的控制,及其他次要的一些标记功能。它继承AQS,它相当于一个不可重入的排他锁.
1) 成员变量
thread表示Worker执行任务的线程,firstTask表示worker执行的第一个任务(对于后来的其他任务它会到任务队列中去获取),completedTasks表示当前worker线程所完成的任务数
/** Thread this worker is running in. Null if factory fails. */ final Thread thread;// 一般不为空,这由ThreadFactory决定 /** Initial task to run. Possibly null. */ Runnable firstTask;//可能为空 /** Per-thread task counter */ volatile long completedTasks;//此工作线程完成的任务数
2) 构造方法
构造方法主要涉及对成员变量的初始化,方法体内调用了父类AQS的setState方法将state置为负数-1,它的主要目的是防止线程被过早中断,直到runWorker
开始执行任务时才清除state的负数状态(成员内部类的一个对象与外部类的对象相互绑定,成员内部类可直接访问外部类的全局变量和实例、静态方法)。
Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker 调用AQS的setState,设置状态 this.firstTask = firstTask; //getThreadFactory是外部类的ThreadPoolExecutor的实例方法,返回一个实现ThreadFactory接口的对象. //newThread根据当前worker所代表(Worker实现了Runnable接口,worker也是Runnable对象)的Runnable对象 //创建一个线程对象。所以this.thread线程启动就会执行worker.run(). this.thread = getThreadFactory().newThread(this); }
3) 方法实现
①run方法
run方法是执行任务方法,它直接委托给外部类ThreadPoolExecutor的runWorker
方法来实现,runWorker
方法的实现细节在之后会详细说明。
/** Delegates main run loop to outer runWorker */ public void run() { // ////当Worker.thread.start()调用后,Worker.thread线程启动,就会执行这里的run方法,run方法又委托给runWorker //换句话说,worker线程启动后,最终会执行runWorker方法。 runWorker(this); }
②与锁相关的方法
isHeldExclusively
、 tryAcquire
、tryRelease
这3个方法均是父类AQS的模板方法所调用的应被重写的方法,其具体原理在之前AbstractQueuedSynchronizer实现原理分析帖子中做过说明,这里不再细说。
lock
、 tryLock
、unlock
、isLocked
这4个方法也与显式锁ReentrantLock实现原理基本一致,之前对ReentrantLock的实现做过说明,这里也不再细说。
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) { //与ReentrantLock的区别在于,这里未检测在释放锁前是否已获得锁 setExclusiveOwnerThread(null); setState(0); return true; } public void lock() { acquire(1); } public boolean tryLock() { return tryAcquire(1); } public void unlock() { release(1); } public boolean isLocked() { return isHeldExclusively(); }
③interruptIfStarted中断线程,调用此方法可以在任务启动后中断线程。
void interruptIfStarted() { Thread t; //state不能小于0,为负数表明worker线程还未启动 //(在构造方法中将state初始为-1,在worker线程启动后runWorker方法开头处的w.unLock会将state置为0) //!t.isInterrupted()如果线程已经是中断状态,也不需要再去中断它了。 if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { t.interrupt(); } catch (SecurityException ignore) { } } }
3 内置的拒绝策略
ThreadPoolExecutor
内部实现了4种拒绝策略,默认使用AbortPolicy
策略,这4种拒绝策略都实现RejectedExecutionHandler
接口,这4个类都是ThreadPoolExecutor
的静态内部类。当线程池执行器饱和时,会调用RejectedExecutionHandler的rejectedExecution
方法处理任务。
CallerRunsPolicy
, 使用任务提交者的所在线程执行任务;AbortPolicy
,直接抛出异常,这是默认的拒绝策略;DiscardPolicy
, 不执行任务,将任务丢弃;DiscardOldestPolicy
,丢弃队列中最近的任务,然后执行当前任务
public static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } //使用调用者的线程执行任务 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } } public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } //直接抛出异常 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } } public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } //啥也不做,丢弃任务 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } } public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } //丢弃队列中最近的任务,然后执行当前任务 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
4 静态常量与成员变量
ThreadPoolExecutor
有一个重要的成员变量ctl
,它是一个int
型的原子变量,它是线程池执行器状态控制的主要属性。它复合了线程池执行器的两个重要状态,一个是workerCount,它表示有效线程数,另一个是runState,它表示线程池执行器是否正在运行、正在关闭等。ctl共有32个二进制位,runState占用ctl的高3位,workerCount占用ctl的低29位,可调用runStateOf(ctl)
方法来取ctl的高3位,可调用workerCountOf(ctl)
方法来取ctl的低29位,另外还可调用ctlOf(runState, workerCount)
根据runState、workerCount算出ctl的值。
//线程池主要的状态控制属性 //初始值为-536870912,二进制开形式为 0b10100000_00000000_00000000_00000000 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //workerCount在ctl中的二进制位数,占29位 private static final int COUNT_BITS = Integer.SIZE - 3; //29 //workerCount的最大值, 二进制形式 0b00011111_11111111_11111111_11111111; private static final int CAPACITY = (1 << COUNT_BITS) - 1;//536870911 // runState is stored in the high-order bits //表示ctl中的最高3位的runState值 private static final int RUNNING = -1 << COUNT_BITS;//二进制形式 0b10100000_00000000_00000000_00000000 private static final int SHUTDOWN = 0 << COUNT_BITS;//二进制形式 0b00000000_00000000_00000000_00000000 private static final int STOP = 1 << COUNT_BITS;//二进制形式 0b00100000_00000000_00000000_00000000 private static final int TIDYING = 2 << COUNT_BITS;//二进制形式 0b01000000_00000000_00000000_00000000 private static final int TERMINATED = 3 << COUNT_BITS;//二进制形式 0b01100000_00000000_00000000_00000000 // Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; //c & 0b11100000_00000000_00000000_00000000 } private static int workerCountOf(int c) { return c & CAPACITY; //c & 0b00011111_11111111_11111111_11111111 } private static int ctlOf(int rs, int wc) { return rs | wc; }
workerCount是已被允许启动但不允许停止的工作线程数。 该值可能与活动线程的实际数量暂时不等,例如,当ThreadFactory在被要求创建,但创建线程失败,该值会与之不等。 用户可见的线程池大小为workers.size()
(workers是一个HashSet类型的对象,它是也是一个成员变量,用来存放Worker的容器)。
runState提供线程池执行器主要的生命周期控制,它有以下几种可取的值:
- RUNNING:接受新任务并处理排队的任务
- SHUTDOWN:不接受新任务,但处理已入队的任务
- STOP:不接受新任务 、不处理已入队的任务,并中断执行中的任务
- TIDYING:过渡状态,即将转为TERMINATED。 此时所有任务已终止,workerCount为零,将线程的状态设为TIDYING,并将调用回调方法
Terminated()
- TERMINATED:方法
terminate()
已执行完
runState是有序的,它随时间单调增加,但其生命周期并非一定会经历下面的所有状态。状态转换过程是
- RUNNING -> SHUTDOWN:在调用
shutdown()
时,可能隐式在finalize()
中调用 - RUNNING/SHUTDOWN -> STOP:调用
shutdownNow()
时 - SHUTDOWN -> TIDYING:当任务队列和工作者线程池都为空时
- STOP -> TIDYING:当工作者线程池为空时
- TIDYING -> TERMINATED:当
terminate()
已执行完时
状态变为TERMINATED时,在awaitTermination()
中等待的线程将返回。
检测到从SHUTDOWN到TIDYING间的状态转换并不简单,因为在SHUTDOWN状态期间,任务队列在非空之后可能会变空,反之亦然,但是只有在看到它为空之后才能看到workerCount 为0 。
其它字段
private final ReentrantLock mainLock = new ReentrantLock(); private final HashSet<Worker> workers = new HashSet<Worker>(); private final Condition termination = mainLock.newCondition(); private int largestPoolSize; private long completedTaskCount; //构造方法的要参数对应初始化的成员变量 private final BlockingQueue<Runnable> workQueue; private volatile ThreadFactory threadFactory; private volatile RejectedExecutionHandler handler; private volatile long keepAliveTime; private volatile int corePoolSize; private volatile int maximumPoolSize; private volatile boolean allowCoreThreadTimeOut; private static final RejectedExecutionHandler defaultHandler = new AbortPolicy(); private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread"); private final AccessControlContext acc; private static final boolean ONLY_ONE = true;
mainLock: 一个可重入的排他锁,这个锁主要是保证访问属性workers的线程安全及与之相关清除、标记 。
workers:它保存所有的工作者线程,访问此属性前必须先获得mainLock锁。
termination:一个等待条件,此属性主要为awaitTermination()
方法中的线程通信提供支持。
largestPoolSize:反映线程池实际曾达到的最大线程数 ,访问此属性前必须先获得mainLock锁。
completedTaskCount:线程池已完成的任务数,它只会在工作者线程终止时更新,访问此属性前必须先获得mainLock锁。
workQueue、 threadFactory、 handler、 keepAliveTime 、corePoolSize 、maximumPoolSize这6个属性,在之前的文章中有过说明,这里不再赘述。
allowCoreThreadTimeOut: 此属性默认为false. 如果它为false,则即使处于空闲状态,核心线程也保持活动状态; 如果为true,则核心线程使用keepAliveTime超时等待任务。
defaultHandler:默认的拒绝策略,当线程池饱和后,只要有新任务到达它就会直接抛出异常。
shutdownPerm 、acc:均是安全权限相关的字段。
ONLY_ONE: 中断时默认只中断一个工作者线程,tryTerminate
方法会用到此常量
5 构造方法
ThreadPoolExecutor
有4个构造方法,分别需要若干个参数,构造方法只简单地涉及对成员变量的初始化,其参数个数最多的构造方法共有7个参数,其他的构造方法都是直接调用这个构造方法来实现的(各个参数的含义在线程池ThreadPoolExecutor简介 有详细说明)。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
6 主要方法
execute是线程池执行器的入口方法,它会调用addWorker创建并启动(thread.start)工作者线程,而工作者线程启动后又会调用runWorker去执行任务。因此可以看出execute、 addWorker 、runWorker 是线程池执行器最重要的3个方法(点击绿色的方法名快速跳至目标方法)。
1) 成员变量ctl相关方法
runStateOf(ctl)
方法来取ctl的高3位,获取runState,
workerCountOf(ctl)
方法来取ctl的低29位,获取workerCount
ctlOf(runState, workerCount)
根据runState、workerCount算出ctl的值。
runStateLessThan(int,int)
返回第一个参数(表示runState)是否小于第二个参数的布尔值
runStateAtLeast
返回第一个参数(表示runState)是否大于等于第二个参数的布尔值
isRunning(int)
返回runState是否为RUNNING(接受新任务并处理排队的任务)的布尔值
compareAndIncrementWorkerCount(int)
尝试CAS更新ctl,将workerCount加1
compareAndDecrementWorkerCount(int)
尝试CAS更新ctl,将workerCount减1
decrementWorkerCount(int)
CAS自旋更新ctl,只有成功将workerCount减1,方法才能返回
advanceRunState(int targetState)
将runState设为targetState,若runState已经至少targetState级别则不改变原runState值。
private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; } private static boolean runStateLessThan(int c, int s) { return c < s; } private static boolean runStateAtLeast(int c, int s) { return c >= s; } private static boolean isRunning(int c) { return c < SHUTDOWN; } private boolean compareAndIncrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect + 1); } private boolean compareAndDecrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect - 1); } private void decrementWorkerCount() { do {} while (! compareAndDecrementWorkerCount(ctl.get())); } private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; } }
2) interruptWorkers系列方法
1) interruptIdleWorkers(boolean)
interruptIdleWorkers的实现比较简单,它在执行核心逻辑之前要先获取两类锁,一个锁是mainLock锁,另一个锁是Worker本身的锁。它遍历所有Worker中对应的线程,若线程是未被中断且是空闲线程就中断此线程 。若参数onlyOne是true,则最多只会中断一个空闲线程。
private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock();//获取mainLock try { for (Worker w : workers) { Thread t = w.thread; //线程已经是中断状态就不再中断它 //尝试获取worker锁,允许抢锁失败。 //若抢锁失败表明worker线程正在执行任务,它不是空闲线程,准备去获取下一个worker锁 if (!t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne)//onlyOne是true,就只中断一个空闲线程,然后退出 break; } } finally { mainLock.unlock(); } }
2) interruptIdleWorkers()
interruptWorkers()
中断线程池中所有的空闲线程 ,我们来看看interruptWorkers()如何实现的。
interruptIdleWorkers()
直接委托给interruptIdleWorkers(boolean)
去实现,上面已经对interruptIdleWorkers(boolean)
分析过了,这里就不再说了。
private void interruptIdleWorkers() { interruptIdleWorkers(false); }
3) interruptWorkers()
interruptWorkers()
中断所有已启动线程, 我们来看看interruptWorkers()如何实现的。
interruptWorkers方法很简单,它先获取mainLock锁,然后遍历所有worker线程,并中断已启动的worker线程。
private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) w.interruptIfStarted();//中断已启动的worker线程(active thread,即线程的start方法已被调用) } finally { mainLock.unlock(); } }
3) terminate系列方法
(1) isTerminating()
isTerminating()
返回线程池执行器是否正在被终止的布尔值,此方法不是ExecutorService接口中的方法,这是ThreadPoolExecutor自身添加的一个API。这种状态一般出现在①shutdown
、②shutdownNow
、③ tryTerminate
方法调用后(tryTerminate中CAS成功将runState更新为TIDYING但调用terminate()方法还未执行完的时候)。
public boolean isTerminating() { int c = ctl.get(); //runState>=SHUTDOWN 且runState<TERMINATED ,那么runState则可能是SHUTDOWN、STOP、TIDYING其中之一 return ! isRunning(c) && runStateLessThan(c, TERMINATED); }
(2) isTerminated()
isTerminating()
返回线程池执行器是否已被终止的布尔值。
public boolean isTerminated() { //runState>=TERMINATED ,此时runState只能是TERMINATED return runStateAtLeast(ctl.get(), TERMINATED); }
(3) awaitTermination()
awaitTermination()阻塞等待所有任务完成。此方法需要设置超时时间,它会阻塞当前线程直到所有任务完成(返回ture)或发生超时(返回false)或当前线程被中断。
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock mainLock = this.mainLock; mainLock.lock();//获取锁 try { for (;;) { //runState是否为TERMINATED 。TERMINATED状态时,所有任务已终止,线程池为空。 if (runStateAtLeast(ctl.get(), TERMINATED)) //已经是TERMINATED了,返回true return true; if (nanos <= 0)//已经超时,返回false return false; //当前线程阻塞等待, //直到“达到超时时间”或“被termination.signal通知"(tryTerminate会调用termination.signalAll) 时 //当前线程才能被唤醒 nanos = termination.awaitNanos(nanos); } } finally { mainLock.unlock(); } }
(4) tryTerminate()
tryTerminate()
检查runState否应转为TERMINATED状态,若状态应该转换则执行相应的teminate工作.
其实现细节是:
①若是在“runState是RUNNING状态”或“runState至少是TIDYING状态”或“runState是SHUTDOWN但队列中还有任务”这三种情况下,将runState不能转为TERMINATED ,方法直接返回。反之则进入下一步。
②再检查线程数workerCount是否为零,若workerCount不为零则调用interruptIdleWorkers中断一个空闲线程 ,反之则进入下一步。
③先获取mainLock锁 ,然后CAS尝试将runState设为TIDYING(这里cas更新失败将自旋重试),再然后执行terminated()
(空方法,留给子类实现)方法,待terminated()执行完后,再将runState无条件设为TERMINATED并唤醒等待termination条件的所有线程
final void tryTerminate() { for (; ; ) { int c = ctl.get(); if (isRunning(c) ||//runState是RUNNING状态 runStateAtLeast(c, TIDYING) || //至少是TIDYING状态 (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty()))//runState是SHUTDOWN但队列中还有任务 //这三种情况下不能将runState转为TERMINATED,方法直接返回 return; //runState可以转为TERMINATED,但池中还有一些线程,就中断池中一个空闲线程,然后方法返回 if (workerCountOf(c) != 0) { // Eligible to terminate interruptIdleWorkers(ONLY_ONE);//中断一个空闲线程 return; } //runState可以转为TERMINATED且池中没有任何线程时 // final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //尝试CAS更新,将runState设为TIDYING // (TIDYING状态表示所有任务都已终止且线程数workerCount为零) if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { try { terminated();//空方法,留后子类实现 } finally { //terminated执行后,无条件地将runState设为TERMINATED状态 //(TERMINATED状态表示terminated方法执行完成) ctl.set(ctlOf(TERMINATED, 0)); //唤醒等待termination条件的所有线程 termination.signalAll(); } return; } } finally { mainLock.unlock(); } // else retry on failed CAS } }
4 )addWorker系列方法
(1) addWorker(Runnable,boolean)
addWorker是一个重要的方法,它的主要作用是启动工作者线程Worker,其返回值表示启动Worker是否成功。它有两个参数,第一个参数是新创建线程的第一个执行的任务(可以为空),第二个参数是表示是否为核心线程的布尔值.
它的主要逻辑分为两部分
①第一部分是两层for循环自旋,它主要是检查runState、workerCount,并将workerCount加1 。
细节上是:先检查执行器是被关闭且工作队列为空,若是,则直接返回false。然后再检查线程数是否超出给定的边界值(核心线程数或可允许最大线程数值),若超出则直接返回false。尝试CAS更新workerCount,将workerCount加1,若CAS更新成功,则退出for循环,进入下一部分,若CAS更新失败,则需再次进入内循环自旋重试。若runState被其他线程修改了,则要重新进入外层循环重试。
②第二部分主体是一个try-finally块,它主要先获取mainLock锁,再向成员变量workers中添加一个worker对象,若添加失败则调用addWorkerFailed进行回滚。
细节上是:先尝试创建并启动一个新的worker(worker.thread.start()启动后,runworker方法会执行)。如果线程工厂无法创建线程(创建的线程为null),将返回false。 如果线程池已停止或即将关闭,也将返回false。 如果worker线程启动失败(由于线程工厂返回null或发生异常),将调用addWorkerFailed进行回滚。
private boolean addWorker(Runnable firstTask, boolean core) { /** * 主要是检查runState 和workerCount,时机合适就将workerCount加1 */ retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c);//获取runState // Check if queue empty only if necessary. //如果线程池已关闭且工作队列为空,添加Worker失败,直接返回false if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; for (;;) { int wc = workerCountOf(c);//获取线程数workerCount if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))//不能大于corePoolSize 、maximumPoolSize //线程数大于规定的线程数(最大容量的线程数,配置的核心线程数、配置的可允许最大线程数) // ,添加Worker失败,返回false return false; if (compareAndIncrementWorkerCount(c))//CAS失败,需要再次进入内循环自旋重试 //workerCount加1成功,退出外层for循环 ,线程数已更新, // 接下来进入实际添加的向成员变量workers中Worker操作 break retry; c = ctl.get(); // Re-read ctl if (runStateOf(c) != rs)//runState被其他线程修改了,需要跳到外层for循环的开头处重试 continue retry; // else CAS failed due to workerCount change; retry inner loop } } /** * 向成员变量workers中添加worker, * 若无法添加worker或线程启动失败,则要调用addWorkerFailed进行回滚 */ boolean workerStarted = false;//worker线程是否启动的标志 boolean workerAdded = false;//worker是否添加成功的标记 Worker w = null; try { w = new Worker(firstTask); final Thread t = w.thread; //t是线程工厂创建出来的线程,可以自己重写ThreadFactory接口的newThread方法, // newThread返回值是否为空不确定,这里有必要对t进行非空判断 if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock();//先获取锁 try { // Recheck while holding lock. // Back out on ThreadFactory failure or if // shut down before lock acquired. int rs = runStateOf(ctl.get()); //线程池处于RUNNING状态或虽处于SHUTDOWN状态但任务为空 ,总之线程池还是可用的 if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { //预先检查线程是否已经被启动了 if (t.isAlive()) // precheck that t is startable //线程已预先被启动了,抛出异常 throw new IllegalThreadStateException(); workers.add(w);//添加worker对象到workers集合中 int s = workers.size(); //检查更新largestPoolSize(表示线程池实际曾达到的最大线程数) if (s > largestPoolSize) largestPoolSize = s; workerAdded = true;//更新worker是否添加成功的标记 } } finally { mainLock.unlock();//释放锁 } if (workerAdded) {//worker成功添加后,启动线程 t.start();//worker.run方法将执行,worker.run又会调用runWorker() workerStarted = true;//更新worker线程是否启动的标志 } } } finally { if (! workerStarted) //添加worker失败,(根据前面的逻辑可看出,在未发生异常时,workerAdded若是false,workerStarted则也为false) //就调用addWorkerFailed(),对addWorker方法进行回滚 addWorkerFailed(w); } return workerStarted; }
(2) addWorkerFailed(Worker)
addWorkerFailed
主要是回滚创建worker线程的失败。
它先要获取mainLock锁,然后它做了3件事:
①从workers中移除这个worker;
②将workerCount减1;
③检查runState否应转为TERMINATED状态,若是则执行相应的teminate工作。
private void addWorkerFailed(Worker w) { final ReentrantLock mainLock = this.mainLock; mainLock.lock();//先获取锁 try { if (w != null) workers.remove(w);//从workers中移除worker decrementWorkerCount();//将workerCount减1 tryTerminate();//尝试终止线程池 } finally { mainLock.unlock(); } }
5) runWorker相关方法
(1) runWorker(Worker)
runWorker(Worker)
主要从任务队列中获取任务执行。核心逻辑:
①将Worker的state从-1置为0(调用worker.unlock),保证之后worker线程能被中断、worker锁能被获取。
②到worker.firstTask属性或任务队列中获取任务。若获取的任务不为空就进入下一步,反之则worker线程准备终止,进入步骤6。
③获取woker锁,准备执行任务。
④检查runState,若runState是STOP级就确保当前线程是中断的,若runState不是STOP级就确保当前线程之后不是中断的。
⑤调用task.run开始执行任务,捕获执行任务过程中可能出现的异常。在任务执行完后,将worker的任务完成数completedTasks加1,再释放worker锁。再次获取任务,跳回步骤2。
⑥在worker线程即将终止退出(包括因异常退出的情况)时,执行processWorkerExit方法处理worker终止的后续工作
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask;// //在获取w.firstTask后,将w.firstTask设为空,因为之后worker会到任务队列中获取任务 w.firstTask = null; //这里并不是真的释放锁,而只是将父类AQS的state从初始的-1置为0。 //否则worker线程不能被中断(worker初始化时state为-1,interruptIfStarted方法中要求state>0才中断线程), //worker锁也一直无法被获取(尝试获取锁时compareAndSetState(0, 1)返回true才能成功抢锁,若state为-1,它永远返回false) w.unlock(); // allow interrupts boolean completedAbruptly = true; //worker异常终止的标志 try { //firstTask不空或任务队列中还能获取到任务, while (task != null || (task = getTask()) != null) { //成功获取到worker锁后,表明worker线程就要执行任务,不再是空闲状态了。 //w.isLock可以判断线程是否空闲等待,如果返回false,表明worker线程在空闲等待 w.lock(); // If pool is stopping, ensure thread is interrupted; // if not, ensure thread is not interrupted. This // requires a recheck in second case to deal with // shutdownNow race while clearing interrupt //如果runState是STOP且线程未被中断,就使用wt.interrupt()中断线程,确保wt是中断的; //如果runState不是STOP就用Thread.interrupted()保证之后wt不是中断状态 //(若某线程t是中断状态,调用静态方法Thread.interrupted()会在清除线程t的中断标记后 //返回true,下次调用实例方法t.isInterrupted()将返回false,这是因为中断标记之前已被清除) if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { beforeExecute(wt, task);//空方法,留给子类实现 Throwable thrown = null; try { task.run();//执行任务 } catch (RuntimeException x) { thrown = x; throw x; } catch (Error x) { thrown = x; throw x; } catch (Throwable x) { thrown = x; throw new Error(x); } finally { afterExecute(task, thrown);//空方法,留给子类实现 } } finally { task = null;//执行完将任务赋空 w.completedTasks++;//已完成任务数加1 w.unlock(); } } completedAbruptly = false;//worker没有因异常死亡 } finally { processWorkerExit(w, completedAbruptly);//清除和标记woker终止后的后续工作 } }
(2) getTask()
getTask()
从任务队列获取任务。其核心逻辑:
①检查runState,若runState状态表明执行器不需要再执行任务(“runState>=STOP” 或 “runState>=SHUTDOWN且任务队列为空”)时,将workerCount减1,返回空任务,此worker线程即将终止。反之则进入下一步
②若当前线程数大于maximumPoolSize或等待任务出队超时或任务队列为空时,就尝试CAS将workerCount减1,反之则进入步骤3。 若CAS更新workerCount成功则返回空任务,反之则自旋重试,跳回步骤1。
③阻塞等待任务出队,如果任务出队成功,就返回这个任务,反之则自旋重试,跳回步骤1。
private Runnable getTask() { boolean timedOut = false;//Did the last poll() time out?任务出队是否超时的标志 for (;;) { int c = ctl.get(); int rs = runStateOf(c); // Check if queue empty only if necessary. //“runState>=STOP” 或 “runState>=SHUTDOWN且任务队列为空”, // 表明执行器已经关闭了,worker线程将终止,返回空任务,worker不再执行任务。 if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount();//因工作线程退出,workerCount减1 return null; } int wc = workerCountOf(c); // Are workers subject to culling? //是否要应用超时策略的布尔值(中断空闲线程) boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; //wc > maximumPoolSize workerCount大于maximumPoolSize,因为maximumPoolSize被重设了 // timed && timedOut 在运用超时策略时最终还真的等待超时了 // "wc >1 || workQueue.isEmpty()"当前只有一个线程或任务队列空了 if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { //尝试CAS将workState减1 if (compareAndDecrementWorkerCount(c)) //CAS更新成功,返回空任务 return null; continue;//CAS更新失败,自旋重试获取任务 } try { //如果要应用超时策略,就等待指定时长让任务出队, //若不应用超时策略,就无限长时间地等待任务出队 Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r;//成功出队了,返回此任务 timedOut = true;//poll返回null,等待超时了 } catch (InterruptedException retry) { timedOut = false; } } }
(3) processWorkerExit(Worker,boolean)
processWorkerExit(Worker,boolean)
处理worker线程终止退出的后续扫尾工作。
其主要逻辑:
①若worker线程是因异常而突然终止的,就将workerCount减1
②获取manLock锁,将worker.completedTasks同步到ThreadPoolExecutor.completedTaskCount中,从workers中移除这个即将终止的worker
③检查runState是否应转为TERMINATED状态及与之相关的处理
④当runState<=STOP时,如果时机合适就启动一个新worker来替代即将终止的worker
private void processWorkerExit(Worker w, boolean completedAbruptly) { if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted //worker因异常而终止,workerCount不能自适应改变,手动将workerCount减1 decrementWorkerCount();// final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //当一个worker终止时,需要将其completedTasks同步到ThreadPoolExecutor.completedTaskCount上 completedTaskCount += w.completedTasks; workers.remove(w);//从成员变量workers中移除这个worker } finally { mainLock.unlock(); } tryTerminate();//检查runState是否应转为TERMINATED状态及与之相关的处理 int c = ctl.get(); //runState是RUNNING或SHUTDOWN时,这两种情况下还可以启动worker if (runStateLessThan(c, STOP)) { if (!completedAbruptly) {//worker正常死亡时 判断是需要启动新worker来替代已死的worker //min表示线程池中能长久驻存的线程数(不会因长久空闲等待而终止的线程数) int min = allowCoreThreadTimeOut ? 0 : corePoolSize; if (min == 0 && ! workQueue.isEmpty()) //只有一个长久驻存的线程但队列中还有任务 min = 1; if (workerCountOf(c) >= min) //当前线程数多于能长久驻存的线程数,不需要启动新worker来替代已死的worker,直接返回 return; // replacement not needed } //启动新的worker替代已死worker addWorker(null, false); } }
6) execute(Runnable)
execute(Runnable)方法非常重要,它是ThreadPoolExecutor的入口方法,父类AbstractExecutorService已实现ExecutorService接口中的sumbit 、invokeXXX方法,这些方法的核心逻辑都委托给execute实现,详细说明见之前的文章AbstractExecutorService源码完全解析。
execute(Runnable)的核心逻辑分为三步:
①如果当前有效线程数少于corePoolSize,则调用addWorker尝试启动一个核心线程执行任务。若成功启动,方法就直接返回,反之则进入下一步。
②若执行器还在运行(runState=RUNNING)且任务入队成功,则需要再次检查workerCount和runState, 反之则进入步骤3。若执行器已关闭(runState>RUNNING)且成功将刚入队的任务从队列中移除,则使用拒绝策略处理此任务;反之再检查当前有效线程数是否为零,若实际线程数为零,则新启动一个非核心线程(保证线程池中至少有一个线程)。
③(一般是队列已满)尝试启动一个非核心线程去执行此任务。 如果启动失败则表明执行器已关闭或已饱和,因此使用拒绝策略处理此任务。
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); //先获取原子变量ctl的值 //工作者线程数少于corePoolSize, if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true))//尝试创建核心线程执行任务 return;//成功就返回 c = ctl.get();//若失败(可能是执行器被关闭了或线程启动失败),要重新获取ctl值 } //工作者线程数大于等于corePoolSize,意味着要尝试将任务放入队列到队列中 //isRunning(c)线程池能接受任务 //workQueue.offer(command)任务入队成功 if (isRunning(c) && workQueue.offer(command)) { //重新获取ctl,将再次检查runState和workerCount因为有可能上次检查后线程被终止了或线程池被关闭了 int recheck = ctl.get(); //线程池已关闭时尝试将这个已入队的任务从队列中移除(上面的"workQueue.offer(command)"已成功入队) if (! isRunning(recheck) && remove(command)) //移除任务成功时,使用拒绝策略处理任务 reject(command);// //"线程池已关闭且从任务队列中移除任务失败(可能是任务已被完成了)" 或"线程池还处于RUNNING状态" //将检查池中的线程数是否为0 else if (workerCountOf(recheck) == 0) //线程数为零时, 创建非核心线程,但不立即执行任务(这里的addWorker中的Runnable为空) // 因为之前已经将此任务放入工作队列了,空闲线程会到队列中去获取任务来执行 addWorker(null, false); } //入队失败,可能是因为队列已满,尝试创建一个非核心线程去执行任务 else if (!addWorker(command, false)) //addWorker失败,使用拒绝策略处理任务 reject(command); }
上面的execute中调用了几个我们不熟悉的方法,分别是remove(Runnable)
、reject(Runnable)
,下面我们分别来看看这两个方法。
(1) remove(Runnable)
remove(Runnable)
方法逻辑很简单,就是先将任务从任务队列中移除,再调用tryTerminate()检查是否应转为TERMINATED状态及其相关的处理,最后返回是否成功移除任务的布尔值。
public boolean remove(Runnable task) { boolean removed = workQueue.remove(task); tryTerminate(); // In case SHUTDOWN and now empty return removed; }
(2) reject(Runnable)
reject(Runnable)
直接委托给拒绝策略handler调用rejectedExecution方法。
handler是实现RejectedExecutionHandler接口的对象,表示线程池饱和时的饱和策略rejectedExecution是此接口的唯一方法,它一般在构造方法中指定。
final void reject(Runnable command) { handler.rejectedExecution(command, this); }
7) shutdown系列方法
(1) shutdown()
shutdown()
方法是用来关闭线程池执行器的,它的主要逻辑是:
先将runState至少设为SHUTDOWN级,然后中断池中的空闲线程,调用onShutdown空方法(钩子函数,留给子类实现),最后检查runState是否应转为TERMINATED状态及与之相关的处理。
public void shutdown() { final ReentrantLock mainLock = this.mainLock; mainLock.lock();//先获取锁 try { checkShutdownAccess();//检查权限 advanceRunState(SHUTDOWN);//若runState已至少是STOP级就不做任何处理,反之将runState设为STOP, interruptIdleWorkers();//中断池中的空闲线程 //空方法,留后子类实现,它是一个钩子函数 其子类ScheduledThreadPoolExecutor重写了此方法 onShutdown(); // hook for ScheduledThreadPoolExecutor } finally { mainLock.unlock(); } tryTerminate();//检查runState是否应转为TERMINATED状态及与之相关的处理 }
(2) shutdownNow()
shutdownNow()
方法是用来立即关闭线程池执行器的,它的主要逻辑是:
先将runState至少设为STOP级,然后中断所有已启动的线程,再从任务队列中移除所有待执行的任务,再然后检查runState是否应转为TERMINATED状态及与之相关的处理,最后返回这些待执行的任务列表。
可以看出shutdown
和shutdownNow
之间的区别在于:
①shutdown将runState至少设为SHUTDOWN,而shutdownNow将runState至少设为STOP.
②shutdown只中断空闲线程,而shutdownNow会中断所有线程。换而言之,shutdown不去停止正在执行的任务,而shutdownNow会让正在执行的任务(如果任务能响应中断的话)停止。
③shutdown不去任务队列中移除任务,而shutdownNow会从任务队列中移除所有的任务。换而言之,shutdown之前提交的任务还能被执行,而shutdownNow之前提交的任务不能被执行了。
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock();//先获取锁 try { checkShutdownAccess();//检查权限 advanceRunState(STOP);//若runState>STOP就不做任何处理,反之将runState设为STOP, //中断所有已启动的线程(包括正在执行任务的非空闲线程和等待任务的空闲线程),不响应中断的任务可能无法被终止 interruptWorkers(); tasks = drainQueue();//从队列中移除所有任务 } finally { mainLock.unlock(); } tryTerminate();//检查runState是否应转为TERMINATED状态及与之相关的处理 return tasks; }
shutdownNow()方法体中调用drainQueue()从队列中移除所有任务, 我们来看看drainQueue()如何做的。
① drainQueue()
drainQueue
所实现的逻辑很简单:它只将将工作队列中的所有任务移除,并将这些任务返回。
private List<Runnable> drainQueue() { BlockingQueue<Runnable> q = workQueue; ArrayList<Runnable> taskList = new ArrayList<Runnable>(); q.drainTo(taskList);//BlockingQueue的drainTo方法会一次性取出所有可用元素,在取出后会在队列中删除这些元素。 if (!q.isEmpty()) {//DelayQueue等类型的队列直接出队可能失败,再次用remove方法获取之前出队失败的元素。 for (Runnable r : q.toArray(new Runnable[0])) { if (q.remove(r)) taskList.add(r); } } return taskList; }
(3) isShutdown()
isShutdown()
返回线程池执行器是否被关闭的布尔值。从方法实现上可以看出,它是根据runState的值判断线程池执行器是否被关闭,只要runState不小于SHUTDOWN,执行器就是关闭状态。
public boolean isShutdown() { return ! isRunning(ctl.get()); } private static boolean isRunning(int c) { return c < SHUTDOWN; }
8) 配置相关setter/getter
(1) ThreadFactory
setThreadFactory/getThreadFactory用于设置/获取线程工厂,只要实现ThreadFactory接口就可以自定义线程工厂。
public void setThreadFactory(ThreadFactory threadFactory) { if (threadFactory == null) throw new NullPointerException(); this.threadFactory = threadFactory; } public ThreadFactory getThreadFactory() { return threadFactory; }
(2) RejectedExecutionHandler
setRejectedExecutionHandler/getRejectedExecutionHandler用于设置/获取饱和策略,当线程池和队列均已满时,调用RejectedExecutionHandler.rejectedExecution处理新任务。
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { if (handler == null) throw new NullPointerException(); this.handler = handler; } public RejectedExecutionHandler getRejectedExecutionHandler() { return handler; }
(3) CorePoolSize
setCorePoolSize/getCorePoolSize用于设置/获取核心线程数
public void setCorePoolSize(int corePoolSize) { if (corePoolSize < 0) throw new IllegalArgumentException(); int delta = corePoolSize - this.corePoolSize; this.corePoolSize = corePoolSize;//更新corePoolSize属性 //如果实际线程数已经多于最新的corePoolSize,就中断所有空闲线程。 if (workerCountOf(ctl.get()) > corePoolSize) interruptIdleWorkers(); //“当前实际线程数少于新corePoolSize”且"新corePoolSize大于原来的corePoolSize" 时 //就预先启动足够的新worker线程(最大为新的corePoolSize)以处理队列中的当前任务数, //但是如果在添加worker过程中队列变为空则停止添加。 else if (delta > 0) { // We don't really know how many new threads are "needed". // As a heuristic, prestart enough new workers (up to new // core size) to handle the current number of tasks in // queue, but stop if queue becomes empty while doing so. int k = Math.min(delta, workQueue.size()); while (k-- > 0 && addWorker(null, true)) { if (workQueue.isEmpty()) break; } } } public int getCorePoolSize() { return corePoolSize; }
prestartCoreThread()
方法启动一个核心线程,若所有核心线程已启动则返回false.
ensurePrestart()
方法与prestartCoreThread()
类似,但它能保证池中至少有一个线程。
prestartAllCoreThreads()
方法将一次性启动所有核心线程,若所有核心线程已启动将返回0。
public boolean prestartCoreThread() { //当前线程数小于corePoolSize就创建一个核心线程 return workerCountOf(ctl.get()) < corePoolSize && addWorker(null, true); } void ensurePrestart() { int wc = workerCountOf(ctl.get()); if (wc < corePoolSize) //当前线程数小于corePoolSize创建一个核心线程 addWorker(null, true); else if (wc == 0) //corePoolSize为0,当前线程数也为0,就创建一个非核心线程。池中至少有这个刚启动的线程了 addWorker(null, false); } public int prestartAllCoreThreads() { int n = 0; while (addWorker(null, true))//一次性启动所有核心线程 ++n; return n;//返回此方法启动的核心线程数 }
(4) MaximumPoolSize
setMaximumPoolSize/getMaximumPoolSize用于设置/获取最大可允许创建的线程数
public void setMaximumPoolSize(int maximumPoolSize) { if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) throw new IllegalArgumentException(); this.maximumPoolSize = maximumPoolSize;//更新maximumPoolSize属性 //若当前实际的线程数多于新的maximumPoolSize,就中断所有空闲线程 if (workerCountOf(ctl.get()) > maximumPoolSize) interruptIdleWorkers(); } public int getMaximumPoolSize() { return maximumPoolSize; }
(5) KeepAliveTime
setKeepAliveTime/setKeepAliveTime用来设置/获取线程的最大空闲时间。
public void setKeepAliveTime(long time, TimeUnit unit) { if (time < 0) throw new IllegalArgumentException(); if (time == 0 && allowsCoreThreadTimeOut()) throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); long keepAliveTime = unit.toNanos(time); long delta = keepAliveTime - this.keepAliveTime; this.keepAliveTime = keepAliveTime;//更新maximumPoolSize属性 if (delta < 0)//新的keepAliveTime小于原keepAliveTime,就中断所有空闲线程 interruptIdleWorkers(); } //处理KeepAliveTime的时间单位转换 public long setKeepAliveTime(TimeUnit unit) { return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS); } public long getKeepAliveTime(TimeUnit unit) { return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS); }
默认情况下keepAliveTime,只适用于非核心线程,即核心线程不会因空闲等待太久而被终止, 但使用allowCoreThreadTimeOut()方法并将参数设为true就可改变这种默认效果,使keepAliveTime对核心线程同样有效。
public boolean allowsCoreThreadTimeOut() { return allowCoreThreadTimeOut; } public void allowCoreThreadTimeOut(boolean value) { if (value && keepAliveTime <= 0) throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); if (value != allowCoreThreadTimeOut) { allowCoreThreadTimeOut = value;//更新allowCoreThreadTimeOut属性 if (value)//若允许核心线程超时,就中断所有空闲线程 interruptIdleWorkers(); } }
(6) WorkQueue
getQueue用于获取任务队列。
public BlockingQueue<Runnable> getQueue() { return workQueue; }
9) 状态监控相关方法
(1) getPoolSize()
getPoolSize()
返回当前线程池中的工作线程总数
public int getPoolSize() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // Remove rare and surprising possibility of // isTerminated() && getPoolSize() > 0 //若runState是TIDYING或TERMINATED时,workerCount一定为0(之前在tryTerminate中分析过) //反之就取workers.size() return runStateAtLeast(ctl.get(), TIDYING) ? 0 : workers.size(); } finally { mainLock.unlock(); } }
(2) getActiveCount()
getActiveCount()
返回当前活动(正在执行任务)的工作线程数
public int getActiveCount() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { int n = 0; for (Worker w : workers) if (w.isLocked())//Worker锁被持有,表示正在执行任务 ++n; return n; } finally { mainLock.unlock(); } }
(3) getLargestPoolSize()
getLargestPoolSize()
返回曾经创建过的最大线程数。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过。
public int getLargestPoolSize() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { return largestPoolSize; } finally { mainLock.unlock(); } }
(4) getTaskCount()
getTaskCount()
返回执行器从启动到现在所接受的任务总数。
public long getTaskCount() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { long n = completedTaskCount;//先获取表示完成的任务数的成员变量completedTaskCount for (Worker w : workers) { //还有一些记录有worker中的已完成任务数(尚未同步到completedTaskCount中) n += w.completedTasks; //另外还要加上正在执行的任务(还未完成) if (w.isLocked())//此worker正在执行任务 ++n; } return n + workQueue.size();//最后加上任务队列中的任务数 } finally { mainLock.unlock(); } }
(5) getCompletedTaskCount()
getCompletedTaskCount()
返回执行器完成的任务总数。
public long getCompletedTaskCount() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { long n = completedTaskCount;//先获取表示完成的任务数的成员变量completedTaskCount for (Worker w : workers) //还有一些记录有worker中的已完成任务数(尚未同步到completedTaskCount中) n += w.completedTasks; return n; } finally { mainLock.unlock(); } }
(6) 空实现的钩子函数
除此之外,线程池还提供了3个空方法,beforeExecute
方法在执行一个任务前被调用,afterExecute
方法在一个任务完成后被调用,terminated()
方法在线程池停止时被调用。
我们可继承ThreadPoolExecutor
来实现自己的线程池,并以此为基础重写这3个方法来实现自己的监控逻辑。
10) finalize()
finalize()方法是顶级父类Object的方法,此方法在对象被GC回收前调用,一般用来清理释放占用的资源。ThreadPoolExecutor重写了此方法,其核心逻辑是调用shutdown()
方法关闭执行器。
protected void finalize() { SecurityManager sm = System.getSecurityManager(); if (sm == null || acc == null) { shutdown(); } else { PrivilegedAction<Void> pa = () -> { shutdown(); return null; }; AccessController.doPrivileged(pa, acc); } }
7 工作流程
以sumbit(Runnable/Callable)方法为例,说明线程池执行器ThreadPoolExecutor的主要工作流程。
sumbit(Runnable/Callable)在父类AbstractExecutorService中已有基本实现,但其核心逻辑execute方法仍要子类实现,所以ThreadPoolExecutor实现了excute方法。
submit(Runnable/Callable)方法的主要工作流程:
①它先将Runnable/Callable任务统一封装成FutureTask。那么FutureTask是如何封装原始任务的? FutureTask将Runnable或Callable任务设为它的(若原任务的类型是Runnable就使用适配器模式将其适配为Callable类型)Callable类型属性callable;另外FutureTask也实现了Runnable接口,而它的run()方法核心内容就是执行callable.call、并记录任务结果或任务执行发生的异常信息
②然后执行execute(task)的核心逻辑是addWorker(), addWorker()会启动一个新的工作线程,即worker.thread启动。worker.thread线程启动后,worker.thread线程将执行worker.run()方法,而worker.run()方法又委托给外部类ThreadPoolExecutor的runWorker方法实现。