前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >梁老师小课堂|谈谈线程池

梁老师小课堂|谈谈线程池

作者头像
公众号_松华说
发布2020-11-09 09:50:29
3870
发布2020-11-09 09:50:29
举报
文章被收录于专栏:松华说松华说

线程池的使用场景通常有两大类。

第一类场景是,并发执行,提高吞吐量。比如对多张图片进行校验,校验项有多个。

在这种场景下,很容易出现父子任务,父子任务共用一个线程池的话可能会出现死锁,这个是需要特别留心的。

另外,当使用Future接收多线程的执行结果时,不要在循环中出现结果为失败或者获取超时就中断,这样后面的Future就无处安放了,长时间运行突然并发升高可能会引起服务不可用。

还有一个注意事项是timeout超时叠加问题,这个问题已经有成熟的方法,就是AbstractExecutorService的invokeAll方法,它能让每个任务的超时时间都是相同的。

第二类场景是,线程隔离。一个请求绑定一个线程,请求链路中的所有任务都是同步进行。

在这种场景中,超时时间配置项是需要特别留心的。超时时间过长就会一直占着线程,服务逐渐地无法接收新请求,这种异常在RPC调用中很常见。如果提供者无法做到实时,那么可以使用下面这种方式,也就是接收请求后将其封装成任务,然后放入到业务线程中执行,执行完再回调,这样就不用担心服务拒绝新请求了。

在第一类场景中,可能有多个业务都需要使用线程池,那是否需要配置多个线程池呢?

按照业务的特性来配置不同的核心线程数、不同的拒绝策略,这种区别对待通常能够隔离异常。但是不能无视的一点是,服务器的CPU资源是固定的,大家都在抢占资源,显然这种做法并不能达到理想的隔离效果。

我在工作中看到比较多的线程池策略是,创建一定量不被回收的核心线程,当线程都在忙碌时,新任务将被放到队列中,当队列满了后再创建线程,创建失败就拒绝任务。核心线程数通过Runtime.getRuntime().availableProcessors() 计算得出,理想情况下是CPU核心数,但是在容器这种环境下是不准的,感兴趣的朋友可以在网上检索下:JAVA程序运行在容器有哪些影响。

这里说的,存放排队任务的队列,在并发突然变大时起着缓冲作用,但是会增大响应时长,对于实时交互场景来说是不能接受的。因此,核心线程数配置成多少,是性能压力测试重点关注的关键指标。我们一般通过重写线程池生命周期的afterExecute方法,统计分析队列积压情况,评估核心线程数设置是否恰当。

然而,已经调优过的核心线程数并不总是准确的,当依赖服务的性能变差时,新任务可能无法分配到线程,只能排队执行了,这样响应时长就会出现波动。即使通过配置中心来动态管理参数,也是不能及时止损的。

所以最好的方案是,不使用队列,尽可能创建更多的线程来处理任务,当前没有空闲线程就创建一个新的线程。甚至,还可以通过prestartAllCoreThreads方法,提前初始化核心线程进行预热。使用这种线程池策略,我们需要提前检查服务器ulimit资源限制情况,还需要避免频繁回收线程。

另外,为了避免服务器的CPU利用率、内存利用率出现过载,通常采用限流、降级来保护系统。我们不限制线程数而是限制请求数,是希望优先保证已经在服务区的客户体验,而不是客户越多越好,因为质量比数量更重要。

完,下期见!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 松华说 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档