JVM 线程池扩容机制

在 HotSpot VM 的线程模型中,Java 线程被一对一映射为内核线程(JDK19后已经引入携程 UT)。及一个 LWP 线程对应操作系统内核中的 KLT,Java 在使用线程执行程序时,需要调用操作系统内核的 API,创建一个内核线程,操作系统要为线程分配一系列的资源,当该 Java 线程被终止时,这个内核线程也会被回收。

因此 Java 线程的创建与销毁的成本很高,会增加系统的性能开销。并且线程也不能创建太多,因为CPU切换线程去执行指令时需要处理对应上下文信息。大量的线程将会导致CPU的性能存在一定损耗。毕竟我们CPU的核心数是有限的,如果我们无限制地创建线程还可能导致 OOM。

故此我们主要来看 ThreadPoolExecutor 类的参数:

int corePoolSize [核心线程数]
int maximumPoolSize [最大线程数]
long keepAliveTime [存活时间]
TimeUnit unit [时间单位]
BlockingQueue<Runnable> workQueue [任务队列]
ThreadFactory threadFactory [线程工厂]
RejectedExecutionHandler handler [拒绝策略]

其中的每一个参数都十分的重要,随意设置可能会带来严重的性能问题或者线上问题,那么我们来看看线程池的具体扩容机制:

当有新任务达到线程池时,任务会进入到 BlockingQueue 中,此时核心线程将会对此任务进行执行,如果在执行中又有新任务进入到队列中并且其他核心线程也正在执行这些任务时,后续的任务只能继续存放到 BlockingQueue,直到 到达队列最大长度(如果不设置队列长度,将很容易导致内存溢出)。如果没有设置 BlockingQueue 最大长度,相当于无界队列,你设置的 maximumPoolSize 与 keepAliveTime 参数没有任何效果。

如果设置了 BlockingQueue 最大长度,并且目前任务个数已经达到了 BlockingQueue  最大长度,这个时候才会关注你设置的 maximumPoolSize 值是否大于 corePoolSize,如果大于将会开启新线程执行 BlockingQueue 中的任务,并且新开启的线程存在 keepAliveTime 的时间周期,在指定的时间周期中没有再次执行任何任务则此线程将会被销毁掉。

文章目录

随心笔记

技术无止境 创新不停驻