Java线程池的参数设置

最近面试过一些候选人,面试过程中,我比较倾向于问一些偏基础又较为开放的问题,用来看看候选人基础能力怎么样,比如线程池,提问过程一般类似如下:

我先问候选人平时怎么使用线程池,得到的结果不出意外就是两种:1.我不用线程池,工作中没接触过并发;2.用Executors.newCachedThreadPool;

不管是哪一种回答,我还是希望能从候选人那里得到他们对线程池的理解,因此还是会问一下ThreadPoolExecutorService的几个参数相关的问题,除了基础非常差的候选人外,一般候选人都能回答上corePoolSize, maxPoolSize, BlockingQueue之间的关系:

  • corePoolSize是核心线程数,maxPoolSize是最大线程数,BlockingQueue是任务队列
  • 当有任务提交时,先创建corePoolSize数量的线程,有更多的任务则进入到BlockingQueue,BlockingQueue满了还不够则创建线程数直到macPoolSize
  • 线程空闲一段时间后会被销毁直到线程池中只剩下core数量的线程

回答出这几个参数的作用以及他们之间的关系后,我一般会给一到两个线程池相关的题,看看候选人是否能思考出,比如:

  • 假如提交到线程池中的任务,IO耗时占比是90%,计算耗时占比10%,忽略提交到线程池中的任务数量,在4C8G的机器上,理想情况下线程池中创建多少个线程是最优的

一般平时只埋头写CURD的候选人,难以计算出来,当然也遇到了不少能算出来结果来的,线程数=(1/0.1) * 4 = 40,能算出来的候选人,我会问下其它问题,例如:

  • 假如e有一类cpu密集性的任务,没有IO操作,日常的时候只有1个任务,流量高峰会有50个任务,4C8G的机器上,使用的线程池,如何设置corePoolSize, maxPoolSize以及BlockingQueue的大小

这样的问题,我还没有遇到能回答的候选人,一般得到类似于下的回答:

  • corePoolSize=4个线程,maxPoolSize大点100个,队列大点,1万
  • 2个线程,队列大点1千

因此我会对候选人做一些引导,比如回答core=4, max=50, queue=1w的,我会问他他设置的maxPoolSize有没有作用,明显队列设置成1w,这个队列太大,根本就不会满,maxPoolSize数量的线程永远不会被创建,明显候选人是随意设置的,没有经过思考,这个时间我会让他结合前面一个题再思考思考

这一步后,有些等候人开始回答出用4个线程,队列50,但这样并不是最优的,因为日常每秒1个任务时,只需要一个线程就够了,创建出4个线程,就有3个浪费

很显然,日常只需要一个线程,那么corePoolSize=1,而高峰时候,虽然任务有50个,但是只是4C的机器,对于cpu密集型任务,4个线程是最优的,因此理想情况下maxCorePoolSize=4,最后再看看队列,因为队列满了,max才会被创建,而我们需要让max快速被创建出来,又不会出现任务拒绝,因此,可将队列大小设置成46,那么线程池的行为如下:

  • 提交第一个任务,创建出core,1个线程
  • 提交第二个到第47个任务时,这些任务进入到队列中,此时队列已满
  • 提交第48个任务到第50个任务时,创建出max,此时一共有4个线程
  • 4个线程同时将队列里的46个任务消费完
  • 一段时间后,max - core数量的线程销毁,即销毁3个线程,还剩下一个线程
posted on 2020-11-09 21:01  成功没有捷径  阅读(1657)  评论(0编辑  收藏  举报