求职者小菜
火箭制造设计师:如果让你来设置线程池,那你会怎么做?
小菜:
ExecutorService executorService = Executors.newFixedThreadPool(num);
火箭制造设计师:好的回去等通知吧。
小菜:哦哦,不对,就是先设置核心线程数,最大线程数,阻塞队列…还有…忘了。
火箭制造设计师:好的回去等通知吧。
八股文(面试用):
- 设置核心线程数(corePoolSize),开始时直接启动corePoolSize个线程这些线程叫工作线程。
- 设置队列(workQueque),如果任务数量>核心线程数量,任务进入队列等待
- 设置最大线程数 maxPoolSize, 如果线程池满了还有任务来,这时候会继续生成工作线程处理到来的任务。但是需要maxPoolSize>=到来的任务
- 设置拒绝策略(handler):当额外生成的工作线程(非核心线程)数达到最大,即:工作线程(非核心线程)数== maxPoolSize时,如果还有额外的任务生成,这时候会采取拒绝策略。分别为
-
AbortPolicy
当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。(该策略下,直接丢弃任务,并抛出RejectedExecutionException异常)
只有第一个会抛异常,这个还是默认的拒绝策略 -
DiscardPolicy
当任务添加到线程池中被拒绝时,默认情况下它将丢弃被拒绝的任务。(即该策略下,直接丢弃任务,什么都不做) -
DiscardOldestPolicy
当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
(该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列) -
CallerRunsPolicy
不进入线程池执行,在这种方式(CallerRunsPolicy)中,任务将由调用者线程去执行。
(用于被拒绝任务的处理程序,它直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务。)
- 设置最大等待时间(KeepAliveTime)即空闲时间,当非核心线程数空闲时间到达指定的存活时间后销毁。
- 核心线程的创建不再是按固定的大小一次性创建出来,而是通过ThreadFactory按需创建
求职者小帅
火箭制造设计师:如果让你来设置线程池,那你会怎么做?
小帅:如果是我,我会先设置先设置一个工具类类似于:
public class ExecUtils implements Executor {
void execute(Runnable r);
}
生成一个工作线程woker,通过execute()方法生成的其他线程在没有被调度之前,在队列中等待。
火箭制造设计师:解释一下你的设计思路
小帅:
- 设置有限数量的线程,控制资源利用率
- 设置队列进行缓冲,解耦任务的提交和执行过程
- 解决了每次线程重复创建和销毁带来的系统开销
火箭制造设计师:如果还是不断有线程过来呢?如何优化
小帅:调整最大工作线程数,改成按需生成(由new改成按工厂模式生成线程。ThreadFactory)工作线程数,记为workCount, 当workCount < = corePoolSize时,每有一个任务来就创建一个工作线程。
火箭制造设计师:这样确实可以提升效率,也能减少积压的任务数量。但是如果还是有源源不断的任务来呢?
小帅:嗯嗯~来就不要了,都拒绝掉
火箭制造设计师:这也是一个方法,有没有更好的?
小帅:嗯嗯~
火箭制造设计师:我们可以把超出corePoolSize + 队列数量的额外任务数量当成是特例,也就是短暂的高峰期。
小帅:哦哦,你的意思是这种特例具有偶发性,可以特殊处理?
火箭制造设计师:是的,你继续往下说说看
小帅:那就继续增加工作线程呗。比如说我设置一个最大线程数maxPoolSize,额外的任务数量< maxPoolSize时就继续生成非核心线程处理高峰期的任务。超过最大线程数(>maxPoolSize)就全部拒绝。
类似于这样
火箭制造设计师:
火箭制造设计师:没错,你很聪明嘛,最后一个问题,既然有高峰期,就自然有低谷期。那低谷期你怎么处理了?
小帅:低谷期就把多余创建的线程都销毁了呗,剩余核心线程就够了。
比如我一开始声明非核心线程的空闲时间(KeepAliveTime),时间到了就把空闲的非核心线程销毁。
火箭制造设计师:你被录取了,明天来上班吧
小帅:OK,想问一下。我的负责做什么工作?
火箭制造设计师:我们部门有几颗螺丝有点松动,你负责拧紧一点就可以了