对java线程池ThreadPoolExecutor的理解

应用场景

提高性能

多个任务同步执行,提高性能。

资源隔离,熔断,快速返回

Spring Cloud 里面的 Hystrix 组件,就是基于线程池来做的熔断,资源隔离。
每个请求都对应一个线程池,可以根据任务耗时及并发情况,调整线程池大小。将不同的请求隔离开来(比如:查询,交易,会员…),这样即使某个接口出现问题,不会耗尽系统资源,导致别的接口用不了。

线程池=食堂吃饭排队

其实软件就是现实世界的抽象表示。可以对比食堂吃饭排队来理解线程池。

一个任务一个线程

只要在食堂吃过饭的人都知道,食堂有好几个打饭的窗口。假如每次有人来吃饭开一个窗口,没人就关掉空闲的窗口,你们觉得这样合适吗?每个窗口需要一个分配一片场地,还要配备饭菜,打饭人员。可能一个人过来打个饭1分钟搞定。然后准备这个窗口却需要1个月。要是吃饭的人多了。现实世界不可能存在那么大的空间和资源来创建打饭窗口。

对比软件世界就是:来一个任务创建一个线程。线程创建和打饭窗口创建一样需要大量的资源:,系统调用,内核态到用户态切换,分配,初始化线程堆栈等。每次任务执行都得等待线程创建。要是任务多,也会耗尽系统资源。

灵活调整窗口数量

大家都知道原来21楼食堂只有一个窗口,然后窗口的服务能力有限,我们公司人又多,还有其他公司的人也过来吃,结果导致有相当一部分同学吃不上饭,或者等很久才吃到。大家说这样是不是很不合理。好在后面食堂又增加了两个窗口,现在一共有3个窗口了。经过多次体验之后发现确实速度快很多。基本都能吃上饭了(虽然经常找不到座位,看样子座位也得增加了…)。

对比软件世界就是:任务过多,多开几个线程处理。

食堂比较聪明,他们发现中午吃饭的人比较多。晚上吃饭的人少。于是他们在晚上的时候就只开一个窗口,节约点员工开支,已经摆放菜品等工作。

对比软件世界就是:设置核心线程和最大线程数,当排队人数排满等待队列后就会创建新的线程来处理,不会超过最大线程数 。

不限制排队队列长度

好,那么现在我们先创建好了几个打饭窗口,没有限制排队人数。结果导致排队了几千上万人。然后我们的打饭窗口速度有限,只能提供100人份饭菜。难不成后面排队的就一直在那干等?等到海枯石烂,饿死为止,又或者吵架闹事,拆食堂,导致一个人都吃不了饭?要是食堂能限制排队人数100为止,那该多好。至少后面来的人可以选择去别的地方吃饭,前面的人丝毫不受影响,依旧能有愉快的用餐体验。

对比软件世界就是:ThreadPoolExecutor线程池里面的workQueue队列长度限制,不能太长,不然会导致任务堆积,处理缓慢。甚至OOM内存溢出。

为什么需要线程池

大家应该都知道线程创建成本是很高的

  • 系统调用,内核态到用户态切换
  • 分配,初始化线程堆栈等。

因此每次任务过来new一个线程并不合理。
如果用过阿里编程规约扫描过代码的同学就会发现,有如下提示:
在这里插入图片描述
通过线程池就可以复用事先创建好的线程,以提高性能。

如何创建线程池

阿里编程规范中有提到
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
原因如下:
1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
在这里插入图片描述
图一:Executors 下创建 fixed thread pool
从图一中我们可以看出,Executors.newFixedThreadPool 指定了线程的数量,但是由于使用的LinkedBlockingQueue,由于没有指定其容量大小,LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE);如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。
在这里插入图片描述
图二:Executors 下创建 cached thread pool
图二中,我们可以看出,Executors.newCachedThreadPool 并没有限定线程的数量

直接new ThreadPoolExecutor

new ThreadPoolExecutor(corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(maxBlockingQueue), new JlpayThreadFactory());

通过查阅源码发现如下几个很重要的参数
在这里插入图片描述

  • corePoolSize 核心线程数
    无论什么情况都会保持的线程数
  • maximumPoolSize 最大线程数
    最大的线程数 ,
    当提交的任务大于corePoolSize 核心线程数 +workQueue 队列长度 后再提交的任务才会新增线程处理,不超过maximumPoolSize 最大线程数
  • workQueue 排队队列
    这个一定要设置队列长度,不然会导致OOM /任务处理等待时间过久

如何配置合适的线程池参数

  1. corePoolSize 核心线程数 根据具体的业务情况(IO密集型,还是CPU密集型),通过压测找到最合适的线程数。我们的情况建议30-50。如果是比较空闲的业务可以设置少一些10个左右。
  2. maximumPoolSize 最大线程数 考虑频繁线程切换带来的开销,不能太大了。 如果是比较稳定的并发量,建议和corePoolSize 线程数一样,这样可以避免(maximumPoolSize -corePoolSize )个线程创建销毁的开销。
  3. workQueue 排队队列的长度 这个关键在于业务是否容忍响应慢的情况,排队多了,等待的时间会越长,建议在线程数的两倍以内。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答:Java线程池Java中的一个重点知识,并且在Java的工作中经常会遇到,因此在面试中也是必问的面试题目。以下是一些常见的Java线程池面试题: 1. 谈谈什么是线程池? 2. 为什么要使用线程池? 3. 你们哪些地方会使用到线程池? 4. 线程池有哪些作用? 5. 线程池的创建方式有哪些? 6. 线程池底层是如何实现复用的? 7. ThreadPoolExecutor核心参数有哪些? 8. 线程池创建的线程会一直在运行状态吗? 9. 为什么阿里巴巴不建议使用Executors? 10. 线程池的底层实现原理是什么? 11. 线程池队列满了,任务会丢失吗? 12. 线程池的拒绝策略类型有哪些? 13. 线程池如何合理配置参数? 这些问题涵盖了线程池的基本概念、使用场景、实现原理以及相关的配置和策略等方面的知识。了解这些问题能够帮助面试者更好地理解和应用Java线程池。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [java线程池面试题有哪些?java线程池常见面试题](https://blog.csdn.net/muli525/article/details/123553744)[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^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [(一)【Java精选面试题】线程池底层实现原理(含答案)](https://blog.csdn.net/qq_30999361/article/details/124924343)[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^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值