线程池传递对象参数_一次线程池参数错误引起的线上故障

在JAVA里,我们通常会把没有前后依赖关系的逻辑操作扔到多个线程里并行执行,以提高代码运行效率

同时,我们一般也不会单独显式创建线程,而是通过线程池设置线程。使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。

并且,根据阿里巴巴Java开发规约,线程池也不建议直接使用Executors去创建,而是应该通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

Executors返回的线程池对象的弊端如下:

  • 1)FixedThreadPool 和 SingleThreadPool :允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
  • 2)CachedThreadPool 和 ScheduledThreadPool :允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

好的,这些我都一一遵守了,于是我在Spring项目里创建了这么一个线程池:

24b1b83a9db415d2d396ad8e78520c34.png

springframework的ThreadPoolTaskExecutor底层也是使用的JDK里的ThreadPoolExecutor,所以参数含义是一样的。

说明下几个关键参数的作用机制:

  • 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务;
  • 当线程池中的线程数目达到corePoolSize后,就会把新到达的任务放到缓存队列当中,缓存队列的大小是queueCapacity
  • 当缓存队列中的任务数到达queueCapacity后,再有新任务来时,就会继续创建新的线程去执行任务,直到总的任务线程数到达maxPoolSize
  • 之后再有新的任务进来就会被拒绝,这个时候就会调用RejectedExecutionHandler的rejectedExecution方法来通知调用者,我们可以通过自定义RejectedExecutionHandler来实现自己的拒绝策略,也可以使用JDK内部支持的拒绝策略:ThreadPoolExecutor.AbortPolicy(丢弃任务并抛出RejectedExecutionException异常)、ThreadPoolExecutor.DiscardPolicy(丢弃任务,但是不抛出异常)、ThreadPoolExecutor.DiscardOldestPolicy(丢弃缓存队列最前面的任务,然后重新尝试执行任务)、ThreadPoolExecutor.CallerRunsPolicy(由调用线程处理该任务) 等

11ef6f32140cebad239b47cff90d43a2.png

好了,现在我使用的threadPoolTaskExecutor的参数是从另一个项目拷贝过来的,我心想:这个参数在线上系统运行这么久都没事,那我直接用也没事吧?~

然鹅,事实证明我还是经验太少了...

这个线程池上线后,刚开始运行着也没事,各种系统/业务指标正常;然而好景不长,过了大概4小时后,突然收到大量报警:使用到该线程池的接口全部大量超时,处理时间从原来的150ms以下,突然飙升到10s以上

经分析,应用下游接口RT正常,那只可能是应用自身逻辑处理出问题了。而应用本身逻辑并没有其他改动,那只能是线程池问题了!

主管一看我这线程池参数配置,就知道原因了:这个参数配置下,相当于核心只有4个任务同时在处理,然后10000个任务全部被阻塞在缓存队列里等待了。这样的配置在低并发场景下看不出问题,因为任务少很快就能被处理了,自然不会堆积在队列里等待;但一旦到了高并发场景下,就会出现任务堆积阻塞在缓存队列里,导致RT急剧增加、请求超时的问题

于是在主管的指导下,结合我们的实际业务(面向前台消费者的高并发应用),我们最终把参数配置成如下:

49cac381a9833a3f9872adbefa377dae.png

缓存队列大小queueCapacity为0,说明我们不希望堆积任务在内存里。

至于怎么避免高并发场景下任务可能面临被丢弃的情况,我们主要通过压测、加机器保障资源、应用限流等实现,这个又是另一个话题了,以后有机会可以深入研究下再讲~

参考:

  • 《阿里巴巴Java开发规约》

本文首发于公众号:EnjoyMoving,欢迎关注交流~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值