java进阶-线程池 - C - 1 - ThreadPoolExecutor类
先把图拿出来
这个类想看懂要花点时间:
1.基础知识:位运算,automicInteger概念,volatile意义,基本设计模式
2.里面有几个内部类 CallerRunsPolicy AbortPolicy DiscardPolicy DiscardOldestPolicy ,这几个类呢叫做线程池的饱和策略
3.还有一个worker内部私有类,这个类就厉害了,是一个涉及到AQS的类,AQS相关知识
这篇文章从使用的角度来理解这个类:
Q: 想要获取一个ThreadPoolExecutor,怎么做呢?
A: 该类提供了多个初始化方法:
这里就参数最长的方法进行详细的说明( 短的,说明方法内部以及设置了默认值)
corePoolSize | 核心线程数 |
maximumPoolSize | 最大线程数 |
keepAliveTIme | 超过corePoolSize数量的空闲线程最大存活时间 |
TimeUnit | keepAliveTIme 存活时间的单位 |
workQueue | 工作队列,保存的是提交之后未执行的任务:有多种队列结构:synchronousQueue ArrayBlockingQueue LinkBlockingQueue DelayQueue 等。可以选者无界队列 |
ThreadFactory |
线程工厂,线程创建的地方 |
RejectedExecutionHandler | 饱和(拒绝)策略 ,ThreadPoolExecutor给我们提供了几种方式 CallerRunsPolicy AbortPolicy DiscardPolicy DiscardOldestPolicy, 自己做项目一般都会自己创建一个饱和策略类,只要实现RejectedExecutionHandler |
PS :对于前4个参数,举个网上看到的例子来讲,一个工厂刚开办目标招10个正式员工(正式员工=corePoolSize)干活,而且招聘的人很懒,等任务来不及了在招人,等到厂子生意变好了,发现人手还是不够招几个临时工(临时工=maximunPoolSize - corePoolSize)。然后生意恢复淡季,10个正式员工都没活干了 ,临时工三天没活干(三天=keepAliveTime) 就辞退。
对于后面3个参数,我沿用上面的例子---工厂是小但是机器还是不错的么,ThreadFactory出口的机器,但小工厂承接业务能力有限,最多承接100个单子(100单子= 有界队列 例: LinkBlockingQueue<Runnable>(100)) ,要是工厂有100个单子堆积着了,那就要停止接单子了(停止接单==饱和策略)
Q:创建了类之后,我怎么用这个线程池来提交任务呢?
A : 该类根据多种方式提交任务:
execute(Runnable): (看到这里那想要继续走下去需要将ThreadPoolExecutor 类的变量搞清楚了,看~~飞碟)
1.先是判断runnable任务是否为空
2. 判断当前运行线程数达到是否核心线程数,没达到就addWorker到核心线程组里面-成功->返回
3. 判断线程池是否还在running 且 提交任务待workQueue能成功-->在判断一次线程池运行情况,在running-->addWorker ,已经停止running了,将队列中刚提交的那次任务剔除掉
4.线程在运行,但是任务提交Queue不进去,启动reject() 饱和(拒绝)策略
submit():submit的具体内容在上一篇介绍AbstractExecutorService 的里面
Q : ThreadPoolExecutor的实例创建之后能够修改属性吗?
A :当然可以啦,hohoho! 我们可以 获取和重设corePoolThread / ThreadFactory(这里有个疑问 -细节 :底层是怎么做到切换的?) / RejectedExecutionHandler /超时时间/最大线程数 不仅如此,还给我们提供很多实用方法
Q: 说到这里感觉源码分析的还是比较少啊,都没有学习到比较严谨,周密的思维方式?
A:那我们再来分析2个 逻辑 “浮渣” 的,一个是 addWorker()方法,一个是 tryTerminate()方法
开始硬啃 addWorker() 了:~~ (>-<) 好下一个
开玩笑啦!!! 不着急看源码,先把方法的介绍看一遍:
检查是否可以根据当前池状态和给定边界(核心或最大)添加新工作线程。如果是,则相应地调整工作者计数,并且如果可能,创建并启动新工作程序,将firstTask作为其第一个任务运行。如果池已停止或有资格关闭,则此方法返回false。如果线程工厂在询问时无法创建线程,它也会返回false。如果线程创建失败,或者由于线程工厂返回null,或者由于异常(通常是Thread.start()中的OutOfMemoryError),我们会干净地回滚。
@param firstTask新线程应首先运行的任务(如果没有则为null)。使用初始第一个任务(在方法execute()中)创建工作程序以在少于corePoolSize线程时绕过排队(在这种情况下我们总是启动一个),或者当队列已满时(在这种情况下我们必须绕过队列) 。最初空闲线程通常通过prestartCoreThread创建或替换其他垂死的工作者。
@param core如果为true则使用corePoolSize作为绑定,否则为maximumPoolSize。 (此处使用布尔指示符而不是值,以确保在检查其他池状态后读取新值)。 @return如果成功则为true
这一个东西搞得我头有点大,下一个我有空再搞好了