在阿里巴巴开发手册的并发处理那章提到线程池不允许使用Executor来创建,要用ThreadPoolExecutor的方式来创建
本文就来分析一下为什么不能使用Executor来创建。其实手册下面说明已经说了
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer**.MAX_VALUE**,可能会创建大量的线程,从而导致 OOM。
那为什么允许请求队列和允许创建线程为无穷大的时候会导致OOM呢?这就要先说一下,线程池的工作原理:
从上图可知,当一个任务到线程池其工作原理:
1.如果线程池中的线程数量少于corePoolSize(核心线程数量),那么会直接开启一个新的核心线程来执行任务,即使此时有空闲线程存在.
2.如果线程池中线程数量大于等于corePoolSize(核心线程数量),那么任务会被插入到任务队列中排队,等待被执行.此时并不添加新的线程.
3.如果在步骤2中由于任务队列已满导致无法将新任务进行排队,这个时候有两种情况:
线程数量 [未] 达到maximumPoolSize(线程池最大线程数) , 立刻启动一个非核心线程来执行任务.
线程数量 [已] 达到maximumPoolSize(线程池最大线程数) , 拒绝执行此任务.ThreadPoolExecutor会通过RejectedExecutionHandler(饱和策略),抛出RejectExecutionException异常。
1.允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2.允许的创建线程数量为 Integer**.MAX_VALUE**,可能会创建大量的线程,从而导致 OOM。
那有同学就会问,为什么
1.FixedThreadPool 和 SingleThreadPool允许请求队列长度为无穷大。
2.CachedThreadPool 和 ScheduledThreadPool允许创建线程数量为无穷大。
这里我们就可以看一下他的源码就知道了。
1.FixedThreadPool 和 SingleThreadPool
//SingleThreadPool源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
//newFixedThreadPool源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
不难发现,他们都是用了LinkedBlockingQueue
队列来接受来不及处理的任务。
问题就是在这个队列里,它的默认构造器是Integer.MAX_VALUE。
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
2.CachedThreadPool 和 ScheduledThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
从上述源码中我们不难发现,这两种线程池,线程池大小是不固定的,虽然newScheduledThreadPool传如一个线程数,但是这个数字只是核心线程数,可能还会扩容,直至Integer.MAX_VALUE
等下一篇,再告诉你,拜拜。
及时学习新知识,不用加晚班