ThreadPoolExecutor工作流程
JDK1.5中引入了线程池,合理地利用线程池能有效的提高程序的运行效率,但不当的使用线程池也会带来致命的危害。作为使用最多的ThreadPoolExecutor,很有必要深入理解的其源码与实现原理。
先看一下ThreadPoolExecutor是如何工作的,暂时不看源码,这样会先有一个比较直观的印象有利于后面深入分析源码。
既然是线程池那么提交任务后一定要创建线程用于执行任务,ThreadPoolExecutor创建线程执行提交任务的流程如下。
简单介绍一下,一个任务提交给线程池后,线程池创建线程来执行提交任务的流程。
- 当提交任务时线程池中的来用执行任务的线程数小于corePoolSize(核心线程数),则线程池利用ThreadFacory(线程工厂)创建线程用于执行提交的任务。否则执行第二2步。
- 当提交任务时线程池中的来用执行任务的线程数大于corePoolSize(核心线程数),但workQueue没有满,则线程池会将提交的任务先保存在workQueue(工作队列),等待线程池中的线程执行完其它已提交任务后会循环从workQueue中取出任务执行。否则执行第3步。
- 当提交任务时线程池中的来用执行任务大于corePoolSize(核心线程数),且workQueu已满,但没有超过maximunPoolSize(最大线程数),则线程池利用ThreadFacory(线程工厂)创建线程用于执行提交的任务。否则执行4。
- 当提交任务时线程池中的来用执行任务大于maximunPoolSize,执行线程池中配置的拒绝策略(RejectedExecutionHanlder)。
下图给出了ThreadPoolExecutor更加直观的整体运行图。图中标注1、2、3、4的分别对应上面分析中的第1、第2、第3、第4步。
结合上图补充几点:
- 线程池中创建的用于执行提交任务的线程的引用被Worker对象持有。Worker会去执行提交的任务,如果提交的任务已执行完Worker会循环地从workQueue(即图中的BlockingQueue)中poll或take任务执行。
- 主线程调用ThreadPoolExecutor的prestartCoreThread()或prestartAllCoreThreads()方法可以在任务还没有提交到线程池前,先创建用于执行提交任务的Worker,这些Worker将等待任务提交。
- 线程池饱和时默认地拒绝策略为AbortPolicy策略,抛出RejectedExecutionException异常,上图中CallerRunsPolicy表达的不是默认地拒绝策略,而是CallerRunsPolicy策略是会将提交的任务(Task)交给主线程执行。即主线程调用Task.run()方法。
ThreadPoolExecutor源码分析
ThreadPoolExecutor的UML类图如上图,其中Executor提供最基础的任务执行的抽象void execute(Runnable command)方法,而ExecutorService在其基础上扩展的管理线程池的一些方法shutdown()、shutdownNow()、isShutdown() 与isTerminated()等,同时增加了用三个重载的submit方法,用于获取任务的执行结果。submit可以提交Callable类型的任务,也可提交Runnable类型的任务。AbstractExecutorService类提供了newTaskFor将提交的Callable与Runnable类型任务转为FutureTask,同时提供了sumbit与invoke的默认实现,具体的任务执行逻辑交由子类ThreadPoolExecutor的execute方法。不管是调用submit还是execute的提交的任务,最终都交由ThreadPoolExecutor的execute方法执行。
execute方法是分析ThreadPoolExecutor源码的入口。
分析execute方法前先看一下ThreadPoolExecutor里面的核心变量与类。
//线程池状态与线程池中有效线程数控制变量,AtomicInteger变量的高3位用于//保存线程池状态,低29位用于保存线程池中有效线程数。 //程线程对应状态如下:// 1、RUNNING: 运行中,接收新的任务或处理队列中的任务 值为-536870912// 2、SHUTDOWN: 关闭,不再接收新的任务,但会处理队列中的任务 值为0// 3、STOP: 停止,不再接收新的任务,也不处理队列中的任务,并中断正在处理的任务 值为536870912// 4、TIDYING: 所有任务已结束,队列大小为0,转变为TIDYING状态的线程将会执行terminated() hook 方法 值为1073741824// 5、TERMINATED: 结束,terminated() 已被执行完 值为1610612736private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
与ctl变量有关的操作方法
//获取线程池的运行状态runState//CAPACITY 二进制值为: 00011111111111111111111111111111//~CAPACITY 按位取反为:11100000000000000000000000000000//ctl&~CAPACITY 低29全为0,得到高3位即线程池的runStateprivate static int runStateOf(int c) { return c & ~CAPACITY; }//获取线程池中有效的线程数private static int workerCountOf(int c) { return c & CAPACITY; }//根据runState与workerCount计算出ctl的值private static int ctlOf(int rs, int wc) { return rs | wc; }//判断线程池是否处于运行中private static boolean isRunning(int c) {return c < SHUTDOWN;}
其它核心成员变量
//工作队列,提交任务超过corePoolSize时,任务被保证在workQueue中private final BlockingQueue workQueue;//处理wokers的锁private final ReentrantLock mainLock = new ReentrantLock(); //工作作线程集合private final Hash workers = new HashSet(); //用于支持awaitTermination方法的条件private final Condition termination = mainLock.newCondition(); //曾经创建过的最大工作线程数private int largestPoolSize;//线程池中已完成的总任务数private long completedTaskCount;//线程池创建执行提交任务对应线程时采用的线程工厂private volatile ThreadFactory threadFactory;//线程池饱和时,拒绝策略private volatile RejectedExecutionHandler handler;//allowCoreThreadTimeOut为true时,无任务时情况下核心线程允许存活时间;//线程池中超过核心线程数,那部分工作线程,无任务时情况下核心线程允许存活时间。private volatile long keepAliveTime;//核心工作线程是以超时的方式还是阻塞的方式尝试从workQueue队列里面获取任务,//当以超时的方式获取时,如果在指定时间内还没有获取到任务工作线程run方法将执//行完毕,对应工作线程被GC回收private volatile boolean allowCoreThreadTimeOut;//线程池中核心工作线程数private volatile int corePoolSize;//线程池中最大工作线程数priv