美文网首页
Executors 的问题

Executors 的问题

作者: hemiao3000 | 来源:发表于2021-03-20 13:52 被阅读0次

    7. Executors 的问题

    ThreadPoolExecutor 和 Executors 都是用来创建线程池的,其中 ThreadPoolExecutor 创建线程池的方式相对传统,而 Executors 提供了更多的线程池类型<small>(6 种)</small>,但很不幸的消息是在实际开发中并『不推荐使用 Executors 的方式来创建线程池』。

    无独有偶《阿里巴巴 Java 开发手册》中对于线程池的创建也是这样规定的,内容如下:

    线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的读者更加明确线程池的运行规则,规避资源耗尽的风险。

    说明:Executors 返回的线程池对象的弊端如下:

    1. FixedThreadPool 和 SingleThreadPool :

      允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OutOfMemoryError 内存溢出。

    2. CachedThreadPool 和 ScheduledThreadPool :

      允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OutOfMemoryError 内存溢出。

    为什么不允许使用 Executors ?

    我们先来看一个简单的例子:

    ExecutorService maxFixedThreadPool =  Executors.newFixedThreadPool(10);
    for (int i = 0; i < Integer.MAX_VALUE; i++) {
        maxFixedThreadPool.execute(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
    

    之后设置 JVM(Java 虚拟机)的启动参数: -Xmx10m -Xms10m (设置 JVM 最大运行内存等于 10M)运行程序,会抛出 OOM
    异常,信息如下:

    Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at
    java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:416)
    at
    java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
    at xxx.main(xxx.java:127)

    为什么 Executors 会存在 OOM 的缺陷?

    通过以上代码,找到了 FixedThreadPool 的源码,代码如下:

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());
    }
    

    可以看到创建 FixedThreadPool 使用了 LinkedBlockingQueue 作为任务队列,继续查看 LinkedBlockingQueue 的源码就会发现问题的根源,源码如下:

    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }
    

    当使用 LinkedBlockingQueue 并没有给它指定长度的时候,默认长度为 Integer.MAX_VALUE ,这样就会导致程序会给线程池队列添加超多个任务,因为任务量太大就有造成 OOM 的风险。

    OOM 问题的原因:

    • FixedThreadPool 和 SingleThreadPool 允许请求队列长度为 Integer.MAX_VALUE,可能会堆积大量请求,可能会导致内存溢出;

    • CachedThreadPool 和 ScheduledThreadPool 允许创建线程数量为 Integer.MAX_VALUE,创建大量线程,可能会导致内存溢出。

    另外,使用 ThreadPoolExecutor 能让开发者更加明确线程池的运行规则,避免资源耗尽的风险。

    相关文章

      网友评论

          本文标题:Executors 的问题

          本文链接:https://www.haomeiwen.com/subject/bxkwcltx.html