当前位置: 首页 > article >正文

创建线程池时为什么不建议使用Executors进行创建

有没有想过为什么在创建线程池的时候我们一般都是通过ThreadPoolExecutor来创建线程池,很少使用Executors来创建线程池?

实践出真知,让我们具体在代码里面看看是什么原因~
我们先用Executors来创建一个固定线程的线程池:

    @Test
    public void test2(){
        ExecutorService executorService1 = Executors.newFixedThreadPool(10);
        for(int i=0;i<Integer.MAX_VALUE;i++){
           executorService1.execute(new MyThread1());
        }
    }
}

class MyThread1 implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(10);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

通过指定JVM参数:-Xmx8m -Xms8m 运行以上代码,会抛出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)

其实这里提示的就很明显的,主要是因为LinkedBlockingQueue出了问题,我们再来看一下底层:

Java中的BlockingQueue主要有两种实现,分别是ArrayBlockingQueueLinkedBlockingQueue

ArrayBlockingQueue 是有边界阻塞队列,对于LinkedBlockingQueue 来说如果没有指定大小的话将是一个无边界阻塞队列,而且里面的最大值如果在没有指定大小的情况下可以达到Integer.MAX_VALUE,对于一个无边界队列来说,是可以不断的向队列中加入任务的,所以这个时候就会出现内存溢出的问题。

上面提到的问题主要体现在newFixedThreadPoolnewSingleThreadExecutor两个工厂方法上,并不是说newCachedThreadPoolnewScheduledThreadPool这两个方法就安全了,这两种方式创建的最大线程数可能是Integer.MAX_VALUE,而创建这么多线程,必然就有可能导致OOM。

阿里巴巴java开发手册上也明确说了尽量不用Executors创建线程池:

那既然问题找到了,我们解决问题就行啦~即对BlockingQueue设置初始值就行,这样一个无边界的阻塞队列就可以变成有边界的阻塞队列

 @Test
    public void test2(){
        ExecutorService executorService1 = new ThreadPoolExecutor(10,30,100,TimeUnit.SECONDS
        ,new ArrayBlockingQueue<>(10),new ThreadPoolExecutor.CallerRunsPolicy();
        for(int i=0;i<Integer.MAX_VALUE;i++){
           executorService1.execute(new MyThread1());
        }
    }
}

class MyThread1 implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(10);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

这种情况下,一旦线程提交数超过我设定的数值,就会报一个异常`java.util.concurrent.RejectedExecutionException,这是因为当前队列已经是一个有边界的阻塞队列,一旦请求数量超过我设定的数值,就会抛出一个异常。

除了自己定义`ThreadPoolExecutor`外。还有其他方法。这个时候第一时间就应该想到开源类库,如apache和guava等。这里作者就不展开描述啦~感兴趣的小伙伴可以自己翻阅资料学习哦~


http://www.kler.cn/a/374539.html

相关文章:

  • 根据提交的二维数据得到mysql建表和插入数据实用工具
  • Cuebric:用AI重新定义3D创作的未来
  • 【技术点】用SQL语言操作关系型数据库Mysql中的数据(有练习资料)
  • 【iOS】SDWebImage
  • TDengine 数据订阅 vs. InfluxDB 数据订阅:谁更胜一筹?
  • 【iOS】YYModel初学习
  • 基于深度学习的需求预测
  • 【ES6】
  • 使用ZipOutputStream压缩文件、文件夹,最后输出
  • 高职健康管理专业校内实训基地建设方案
  • 除了wordpress CMS外,还有什么CMS值得我们使用?
  • java开发如何在单例模式下通过锁机制防止并发?
  • QT:子线程更新UI
  • 硅谷(12)菜单管理
  • 批量图片转PDF文件的多种方法详解
  • 哈尔滨三级等保信息安全风险管理指南
  • 超详细的MySQL存储引擎讲解,学习MySQL这些知识你必须要会!
  • kan代码阅读
  • 账户和组管理
  • 若依框架部署到服务器刷新或者是退出登录出现404
  • Spring Boot2.x教程:(十)从Field injection is not recommended谈谈依赖注入
  • PVE修改Ubuntu虚拟机的硬盘大小
  • nginx 根路径同时代理 http ws sse 三种请求
  • WebGL 快速入门构建你的第一个 3D 应用
  • 在浏览器中运行 Puppeteer:解锁新能力
  • USB接口类型及引脚信号详解