微信|三分钟弄懂线程池执行过程

微信|三分钟弄懂线程池执行过程

文章图片

微信|三分钟弄懂线程池执行过程

文章图片


线程池是如何运转的我一直不清楚 , 今天来根据源码梳理下 。
线程池任务提交与运行直接看结果 , 主流程如下:
线程池调用execute提交任务—>创建Worker(设置属性thead、firstTask)—>worker.thread.start()—>实际上调用的是worker.run()—>线程池的runWorker(worker)—>worker.firstTask.run();
如果看不懂上面的流程可以看接下来一步步的分析他们是如何来的 。
线程池基本知识线程池的基本知识点应该都了解了 , 不过这里还是列出几点作为阅读源码的基础 , 以下是创建线程池最关键的7个参数:
corePoolSize:线程池核心线程数量;
maximumPoolSize:线程池会创建最大线程的数量;
keepAliveTime:线程池中大于 corePoolSize 的那部分线程的最大空闲存活时间 。
Unit:存活时间单位;
workQueue:保存等待执行的任务的一个阻塞队列 , 当线程池所以线程都在运行中时再次提交任务 , 任务会保存在阻塞队列中;
threadFactory:创建线程的一个工厂 ,默认为DefaultThreadFactory类;
handler:线程饱和策略 , 如果线程池所有线程都在执行任务 , 并且等待队列也满了的情况下 , 指定的处理方法 , 默认为ThreadPoolExecutor.AbortPolicy 。
execute源码步骤梳理了execute方法源码执行步骤如下图:

从上图可以把execute方法主要分三个步骤:
首先如果当前工作线程数小于核心线程 , 则调用addWorker(command true)方法创建核心线程执行任务 。
其次如果当前线程大于核心线程数则判断等待队列是否已满 , 如果没有满则添加任务到等待队列中去 , 如果工作线程数量为0则调用addWorker(null false)方法创建非核心线程 , 并从等待队列中拉取任务执行 。
最后如果队列已满则会调用addWorker(command false)方法创建一个非核心线程执行任务 。 如果创建失败则会拒绝任务 。
简单来说就是优先核心线程 , 其次等待队列 , 最后非核心线程 。
addWorker方法可以看到execute中最关键的就是addWorker方法 , 它接受两个参数:
第一个参数是要执行的任务 , 如果为null那么会从等待队列中拉取任务;
第二个参数是表示是否核心线程 , 用来控制addWorker方法流程的;
addWorker方法实现主流程如下图:

流程中去除一些异常情况 , 只留了主要流程 , 流程中有一步验证线程数大于核心线程或者最大线程数 , 如果传递的参数core等于true那么运行线程数量不能大于核心线程数量 , 如果为false则当前线程数量不能大于最大 。
addWorker只有两个作用:增加工作线程数量、创建一个Worker并加到工作线程集合中 。
Worker类Worker类就是线程池中执行任务的类 , 主要源码和解释如下图:

所以Worker本身就是一个Runnable , 它有两个属性thead、firstTask;那我们就可以来梳理一下整体的运行流程了:
线程池调用execute—>创建Worker(设置属性thead、firstTask)—>worker.thread.start()—>实际上调用的是worker.run()—>线程池的runWorker(worker)—>worker.firstTask.run()(如果firstTask为null就从等待队列中拉取一个) 。
转了一大圈最终调用最开始传进来的任务的run方法 , 不过通过等待队列可以重复利用worker与worker中的线程 , 变化的只是firstTask;
总结线程池的execute的作用是把任务放到等待队列中或者新建worker并把任务放到worker的firstTask , 最后执行worker中的thread;
Worker中的thread的start方法会执行Worker的run方法;
Worker的run方法会调用线程池的runWorker方法;
runWorker方法则是调用worker的firstTask的run方法 , 达到目的;
好处就是可以重复利用Worker与Worker中的thread , 这也是线程池的优势 。
Java程序员日常学习笔记 , 如理解有误欢迎各位交流讨论!
【微信|三分钟弄懂线程池执行过程】


    推荐阅读