线程池满了如何处理及spring参数设置:

线程池满了如何处理及spring参数设置:

 

 

多线程的问题,不仅仅考虑在代码中用线程池,在spring等上也许配置

并发问题也不是,单纯的在代码中同步,数据库zk等,也不仅仅是在nginx,tomcat调优也在jvm数据库有样的设置地方

 

 

线程池简介

自JDK1.5,Java吊炸天的并发包就提供线程池java.util.concurrent.ThreadPoolExecutor ,先来看看其各个字段的含义: 
corePoolSize 核心线程数,指保留的线程池大小(不超过maximumPoolSize值时,线程池中最多有corePoolSize 个线程工作)。 
maximumPoolSize 指的是线程池的最大大小(线程池中最大有corePoolSize 个线程可运行)。 
keepAliveTime 指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。 
unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。 
workQueue 表示存放任务的队列(存放需要被线程池执行的线程队列)。 
handler 拒绝策略(添加任务失败后如何处理该任务).

关于corePoolSize、maxPoolSize、queueCapacity之间的关系: corePoolSize为初始线程个数,当corePoolSize的线程都在执行中时,则将Runnable临时放入queueCapacity的缓冲队列中等待,当queueCapacity满了时,才会将线程个数从corePoolSize扩展至maxPoolSize,如果此时queueCapacity缓存队列任然是满的,则后续Runnable对象加入其中时就会被abort抛弃

这位兄弟提供了很好的代码说明例子,具体可参见:http://dmwdmc.iteye.com/blog/1882475。例子中有模拟整个线程池都满了抛弃后面任务的场景。

线程池之坑1

说明:如下线程池配置均为使用的spring封装过得线程池。 
坑出现的场景:一个接口,需要四次次访问数据库,而且四次结果之间也没有必然联系,何不把这个四次访问数据库操作分别放入四个线程中同时去访问呢,从而大大节省时间。 
OK,楼主就这么干了,并且这四个线程都丢到一个统一的线程池中去执行。那么坑来了,该接口常常于一天的固定时间有着“惊喜”的访问量,上线第二天,六个tomcat全部挂掉,查看堆dump文件,发现出现了OOM错误,而且六个tomcat几乎相差不多的时间出现。楼主心虚地就想到了自己加的线程池。下面是楼主的线程池配置,各位鉴赏(配置是直接从其他人的配置拷贝过来,没有多想):

    <bean id="resQueryBaseInfoExecutor"
          class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="threadNamePrefix" value="resQueryBaseInfoExecutor-" />
        <property name="corePoolSize" value="5" />
        <property name="keepAliveSeconds" value="100" />
        <property name="maxPoolSize" value="10" />
        <property name="queueCapacity" value="100000" />
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

其中queueCapacity被设置为100000,目的是为了保证所有任务都没接受而不会因为线程池满了而被抛弃,但显然当缓存队列真的到了10W时,OOM应该就不远了… 
楼主深思了原因:corePoolSize过小,导致线程池吞吐量过小,而queueCapacity配置过大,加上吞吐能力差,直接导致等待队列达到10W个对象,导致JVM顺利地OOM了,从而导致整个应用挂掉,造成宕机严重问题。

线程池之坑2

corePoolSize配置小,queueCapacity也配置小,导致线程池吞吐能力差,缓存数量少,很有可能在流量稍微上来之后拒绝后面的线程,导致数据操作丢失,这也是楼主亲身经历的:

    <bean id="resQueryBaseInfoExecutor"
          class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="threadNamePrefix" value="resQueryBaseInfoExecutor-" />
        <property name="corePoolSize" value="5" />
        <property name="keepAliveSeconds" value="100" />
        <property name="maxPoolSize" value="10" />
        <property name="queueCapacity" value="500" />
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

因此综上,正确的估算接口的流量、以及每个线程任务执行的大概时间,计算出每个线程的吞吐量,才能正确设置corePoolSize、maxPoolSize、queueCapacity三个参数。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中的线程池主要是通过使用ThreadPoolTaskExecutor来实现的。ThreadPoolTaskExecutor是Spring基于java本身的线程池ThreadPoolExecutor做的二次封装,主要目的是为了在Spring框架中更方便地使用线程池。它是Spring中默认的线程池。 在Spring Boot中,我们可以使用@Async注解来开启异步任务,并通过@Async("pool")来指定线程池。如果没有指定线程池Spring将使用默认的线程池。另外,我们可以根据需求自定义线程池处理任务。 配置Spring Boot中的线程池可以通过配置文件的形式实现。可以使用ThreadPoolTaskExecutor将线程池的bean注入到IOC容器中,并使用配置文件进行自动配置。在配置文件中,我们可以设置核心线程数、最大线程数、空闲线程存活间、线程队列数量等参数。 总的来说,Spring Boot提供了方便且灵活的线程池配置方式,可以根据需求来选择默认的线程池或自定义线程池处理异步任务。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Springboot自带线程池](https://blog.csdn.net/weixin_45874214/article/details/130446654)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值