线程池使用不当导致内存暴涨

一个非WEB项目的线上服务在高峰期出现内存持续上涨直至宕机的问题,经过排查发现是线程池配置不当所致。文章详细分析了线程池的工作原理,包括核心线程数、最大线程数、阻塞队列、饱和策略等参数,以及无界队列如LinkedBlockingQueue带来的风险。修复方案中采用了有界队列以避免内存耗尽,同时讨论了不同饱和策略的应对方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:最近一个非WEB项目(定时任务运行的核心业务系统),线上服务开始变得不那么稳定。在高峰期,时常有机器的内存持续飙升,并且无法回收,导致服务不可用,最后直接把一个16g内存的服务器跑宕机了(一首凉凉送给自己)。经过排查,最终确定为为线程池导致。

一.线程池

       虽然Java线程池理论,以及构造线程池的各种参数,以及 Executors 提供的默认实现之前研读过,不过线上还没有发生过线程池误用引发的事故,所以有必要把这些参数再仔细琢磨一遍。优先补充一些线程池的工作理论,有助于展开下面的内容。线程池顾名思义,就是由很多线程构成的池子,来一个任务,就从池子中取一个线程,处理这个任务。这个理解是我在第一次接触到这个概念时候的理解,虽然整体基本切入到核心,但是实际上会比这个复杂。例如线程池肯定不会无限扩大的,否则资源会耗尽;当线程数到达一个阶段,提交的任务会被暂时存储在一个队列中,如果队列内容可以不断扩大,极端下也会耗尽资源,那选择什么类型的队列,当队列满如何处理任务,都有涉及很多内容。线程池总体的工作过程如下图:

         线程池内的线程数的大小相关的概念有两个,一个是核心池大小,还有最大池大小。如果当前的线程个数比核心池个数小,当任务到来,会优先创建一个新的线程并执行任务。当已经到达核心池大小,则把任务放入队列,为了资源不被耗尽,队列的最大容量可能也是有上限的,如果达到队列上限则考虑继续创建新线程执行任务,如果此刻线程的个数已经到达最大池上限,则考虑把任务丢弃。在 java.util.concurrent 包中,提供了 ThreadPoolExecutor 的实现。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
}

既然有了刚刚对线程池工作原理对概述,这些参数就很容易理解了:

corePoolSize- 核心池大小,既然如前原理部分所述。需要注意的是在初创建线程池时线程不会立即启动,直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize。若想一开始就创建所有核心线程需调用prestartAllCoreThreads方法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值