菜鸟笔记
提升您的技术认知

三分钟弄懂线程池执行过程-ag真人游戏

线程池是如何运转的我一直不清楚,今天来根据源码梳理下。

线程池任务提交与运行

直接看结果,主流程如下:

线程池调用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,这也是线程池的优势。

网站地图