欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

为何不推荐直接采用 Executors.new 线程池的方式?

程序员文章站 2022-03-22 09:44:21
众所周知,Java并发编程是一大难点所在。其实并不是我们不懂并发原理,而是我们往往忽略了细节,然而,“魔鬼总在细节中”!;作为以Java作为主语言的研发,应该都知道 Executors.new 各种线程池的时候(ScheduledThreadPool除外),底层都是通过 ThreadPoolExecutor来实现的。[延拓]```ThreadPoolExecutor ```的5项基本参数为:int corePoolSize:核心线程数int maximumPoolSize:线程池最大可拥有的...

众所周知,Java并发编程是一大难点所在。

其实并不是我们不懂并发原理,而是我们往往忽略了细节,然而,“魔鬼总在细节中”!;

作为以Java作为主语言的研发,应该都知道 Executors.new 各种线程池的时候(ScheduledThreadPool除外),底层都是通过 ThreadPoolExecutor来实现的。

[延拓]


ThreadPoolExecutor的5项基本参数为:

  • int corePoolSize:核心线程数
  • int maximumPoolSize:线程池最大可拥有的线程数(最高并发量)
  • long keepAliveTime:线程idle态的最大存留时间
  • TimeUnit unit:时间单位,配合 keepAliveTime 使用
  • BlockingQueue workQueue:任务队列(当任务量打满核心线程数 or 最大线程数 时,用来存放排队等待执行的任务)

以下主要以 Executors.newFixedThreadPool(nThreads)进行分析:
为何不推荐直接采用 Executors.new 线程池的方式?

由上图,我们可以明显得出两项信息:

  • 线程池中线程不会进行回收,会一直存活,即使都一直处于idle状态(因为corePoolSize和maximumPoolSize被设置为等大)
  • 任务队列直接采用new LinkedBlockingQueue<Runnable>()方式,是*的,也就是说任务量飙升时会存在内存溢出风险

那还有没有其他信息呢???当然!!!
我们再来看通过Executors.newFixedThreadPool方式调用ThreadPoolExecutor时,存在哪些隐性操作:
为何不推荐直接采用 Executors.new 线程池的方式?
为何不推荐直接采用 Executors.new 线程池的方式?
啊!!!你看,内部直接采用了Executors.defaultThreadFactory(),它会做些什么?是以什么样的方式来给我们提供工作线程呢?
为何不推荐直接采用 Executors.new 线程池的方式?

发现问题严重性了吗?默认提供的工作线程均为非守护线程!
也就是说,如果一旦发生意外,主线程都已经退出了,如果此时我们因为异常而没有关闭线程池的话,进程会作为一个僵尸进程一直存在的!!!

这也是近期排查线上问题时,发现有些小伙伴写代码太过于随意,根本不考虑边界情况以及异常case。

所以,我们平时设计并发编程,采用线程或线程池的时候,多一些思考,可能就会有不一样的结果。

在这里我也只是抛砖引玉,有兴趣的话,可以自己尝试去分析下Executors.new的另外几种方式又会存在哪些潜在风险呢?

本文地址:https://blog.csdn.net/qq_17776287/article/details/110877010