ThreadPoolExecutor的工作原理和参数设置

前言

在面试中经常遇到这样的问题,如:在项目中有没有用到线程池(ThreadPoolExecutor),线程池的工作原理是怎样的,你是如何设置各个线程池参数(如:corePoolSize、maximumPoolSize等)的。

ThreadPoolExecutor有哪些关键参数?

  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数,即允许同时存在的线程的最大数量
  • keepAliveTime:空闲线程存活时间
  • allowCoreThreadTimeOut:是否允许核心线程在空闲时间超时时销毁,默认为false
  • workQueue(BlockingQueue):阻塞队列
  • handler(RejectedExecutionHandler):拒绝策略

ThreadPoolExecutor是如何工作的?

要确定各项参数的合理值,首先得知道ThreadPoolExecutor是如何工作的。当一个任务提交到线程池后,执行流程如下图所示:
线程池原理
不同的拒绝策略对应不同的结果,ThreadPoolExecutor内部实现以下四种:

  • AbortPolicy:抛出异常RejectedExecutionException
  • DiscardPolicy:不做任何处理,直接丢弃当前提交的任务
  • DiscardOldestPolicy:丢弃阻塞队列中最老的任务
  • CallerRunsPolicy:在当前线程执行提交的任务

如何合理的设置各项参数?

了解了ThreadPoolExecutor的执行流程后,下面看下如何设置各项参数。
1.对于线程数的设置,网上流传着一个规则:

  • CPU密集型任务:线程数设置为CPU核心数+1,之所以比CPU数多一个,是因为线程有可能因为某些原因暂停,这时候多出来的那个线程就可以充分利用当前空闲的那个CPU,避免资源的浪费。
  • I/O密集型任务:线程数设置为CPU核心数*2,在I/O期间,线程是阻塞的,此时CPU是空闲的,所以可以相应的增加线程数。

        当然,该规则只是一个参考,在实际应用中,需要根据真实的业务场景确定CPU执行时长和I/O执行时长的占比,从而设置一个合理的值。最好的方式是根据系统的运行情况进行动态设置(利用配置中心),ThreadPoolExecutor是允许在运行期间动态设置corePoolSize和maximumPoolSize的。

2.阻塞队列BlockingQueue的设置:
        不推荐使用无界队列,对于一个运行中的系统,如果我们没有考虑到所有可能发生的情况,使用无界队列有可能因为某些异常情况导致创建了大量的任务,线程池来不及处理,而最终把内存耗完。
        所以,我们要根据任务的提交频率和任务的运行时长,以及允许的任务延迟,计算出一个比较合理的队列大小,同时结合拒绝策略使用,比如,对于不重要的任务,可以采用丢弃策略;而针对重要的任务,系统实在处理不过来的话,可能做相应的告警,通知运维人员进行处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值