你真的了解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吗-队列策略