#多线程学习——ThreadPoolExecutor之不允许使用Executors创建(1)

在阿里巴巴开发手册的并发处理那章提到线程池不允许使用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异常。

OK.现在大致知道了流程池的处理逻辑,也就不难解释为什么,

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<Runnable>队列来接受来不及处理的任务。
问题就是在这个队列里,它的默认构造器是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

OK,知道Executor创建线程池有资源耗尽的风险,那我们应该怎么解决了?

			等下一篇,再告诉你,拜拜。

及时学习新知识,不用加晚班

发布了50 篇原创文章 · 获赞 46 · 访问量 21万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览