最新消息:从今天开始,做一个有好习惯的人。

你真的了解ThreadPoolExecutor吗-队列策略

java体系 迷路的老鼠 7628浏览 1评论

你真的了解ThreadPoolExecutor吗

ThreadPoolExecutor 网上的讲解特别多,主要是针对各个入参的讲解,但是有一个非常重要点被遗漏了,那就是队列的三种类型,每个类型的定义都非常哟代表性,试用的场景也是非常有指向性的。所以了解这三种类型非常有必要。

在开篇,在重新描述一下 ThreadPoolExecutor构造方法的几个入参和含义。

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
long keepAliveTime, TimeUnit unit, 
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

corePoolSize – 池中所保存的线程数,包括空闲线程。

maximumPoolSize-池中允许的最大线程数。

keepAliveTime – 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的 最长时间。

unit – keepAliveTime 参数的时间单位。

workQueue – 执行前用于保持任务的队列。此队列仅保持由execute方法提交 的 Runnable任务。

threadFactory – 执行程序创建新线程时使用的工厂。

handler – 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。 ThreadPoolExecutor是 Executors 类的底层实现。

我们一般来讲,新的请求过来,会创建核心线程数,如果核心线程数满了,就会进入队列,如果队列也满了,就会创建新的线程,直到达到设定的最大线程数。如果最大线程数和队列都慢了,则会执行指定的异常处理程序。

不管哪种策略都必须遵循上述流程,这也是下文讲述队列策略的基础。

1.直接提交SynchronousQueue。他会将任务直接提交给线程,不保持请求。如果线程数不够,则会创建一个新的线程。所以在此时,如果设置了有界的maximumPoolSize,那么创建失败的可能性就非常大了。 如果选择了这种策略,那么 maximumPoolSize最好设置成无限大。

我们来看一下 ThreadPoolExecutor 里的一段代码

/**
 * Create the BlockingQueue to use for the ThreadPoolExecutor.
 * <p>A LinkedBlockingQueue instance will be created for a positive
 * capacity value; a SynchronousQueue else.
 * @param queueCapacity the specified queue capacity
 * @return the BlockingQueue instance
 * @see java.util.concurrent.LinkedBlockingQueue
 * @see java.util.concurrent.SynchronousQueue
 */
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
   if (queueCapacity > 0) {
      return new LinkedBlockingQueue<Runnable>(queueCapacity);
   }
   else {
      return new SynchronousQueue<Runnable>();
   }
}

这是创建队列的一个方法,当你预设的队列容量小于等于0时,那么就是用SynchronousQueue队列策略。否则使用LinkedBlockingQueue。为什么呢?因为 SynchronousQueue是直接提交的,他不需要保持请求。

2.无界队列。比如前面提到的LinkedBlockingQueue就是无解队列。如果不手动指定容量,他的最大容量是 Integer.MAX_VALUE,所以一般也定义为无界队列。前面也说到了,如果队列满了,就会创建新的线程,直到到达最大线程数。如果我们设置了一个无界队列,那么最大线程数,是没有意义的,他会将请求一直存放在无界队列,等待核心线程释放。当然这种实际场景并不常见。

3.有界队列ArrayBlockingQueue,我们在创建线程池时,如果选择这种队列策略,那么必须制定队列的大小,所以叫有界队列。这种使用场景,一般是防止资源耗尽。这种一般比较适用于硬件配置不高,且对于程序的处理失败有一定的容忍。

一般情况下,在我们的使用场景中用到的最多的,容错性最强的,是初始化一个有限容量队列的无界队列的线程池,这种线程池的弹性最好,容错性也比较强。但是,前提条件是需要预估好最大线程数和队列长度。具体方案,具体分析,这里就不做分析。

后面有时间,再把这三种策略的实现方式写一写。

转载请注明:迷路的老鼠 » 你真的了解ThreadPoolExecutor吗-队列策略

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (1)

  1. 应用于外卖点单、淘宝下单、账单处理、各种叫号、各种请求的么 😉
    wa5年前 (2020-07-10)回复