当前位置:首页 > 科技  > 软件

不同业务使用同一个线程池发生死锁

来源: 责编: 时间:2024-09-10 09:50:21 234观看
导读在我们进行代码开发时,我也见过很多全局注册一个自定义线程池(也有可能不是自定义的,直接使用更不推荐Executors 创建的线程池),也许是业务量不高、也许是其他原因,反正全局可这一个线程池使劲造。一、看个代码业务逻辑代码

在我们进行代码开发时,我也见过很多全局注册一个自定义线程池(也有可能不是自定义的,直接使用更不推荐Executors 创建的线程池),也许是业务量不高、也许是其他原因,反正全局可这一个线程池使劲造。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

一、看个代码

业务逻辑代码:bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

自定义线程池 BizThreadPool 代码如下:bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

通过上方的代码示例,如果你还没有看出问题,那你可以停留几秒思考一下。bO928资讯网——每日最新资讯28at.com

自定义线程池创建,使用的这个队列,嗯......,大家工作中一定不要这么用,此处只是为了做演示使用。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

如果你已经看出来了问题所在,也希望你能继续看下去,验证一下咱们是不是想的相同。bO928资讯网——每日最新资讯28at.com

二、有啥问题

经过短暂几秒钟的思考之后,决定还是运行一下 Demo 看看现象。bO928资讯网——每日最新资讯28at.com

封装一个 controller 直接启动 Springboot 程序,Java 启动。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

启动成功之后调用 GET http://localhost:8080/test/test,输出结果如下。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

按照我们的预期,日志中应该也要输出子任务才对啊,怎么创建的子任务没有输出呢,看现象应该是没有执行。bO928资讯网——每日最新资讯28at.com

那我们先执行一下 jstack 命令看一下线程相关的信息,输出信息中其中一段如下所示。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

通过上面的堆栈信息可以看出,主线程在将父任务执行完成之后,开启了一个CountDownLatch并等待3个子任务执行完成。bO928资讯网——每日最新资讯28at.com

问题就在这,一直等待,一直等不到结果,所以就是我们刚开始看到的结果,只有父任务执行了,子任务并没有执行。bO928资讯网——每日最新资讯28at.com

一次调用没有响应,多次调用之后,达到服务器资源瓶颈时系统就该发生崩溃了。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

那么子任务为何没有执行到呢?bO928资讯网——每日最新资讯28at.com

三、小试牛刀

首先我们从头开始捋一下,先看下线程池的配置。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

我们在创建自定义线程池时,核心线程与最大线程都设置的1,那我们直接修改最大线程数量,让线程池有线程可以执行子任务不就行了吗?bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

对于生产中,核心线程与最大线程一般也不会设置为1,但是哪怕你设置为10、100、1000,极端情况下也会出现本文后面将要讲述的问题。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

说干就干,创建自定义线程池的代码变为了如下形式。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

非常自信的你重启程序,然后调用接口,最终傻眼了,怎么没变化?bO928资讯网——每日最新资讯28at.com

如果你修改完最大线程数就去重启程序的话,说明线程池的工作原理你已经忘了!bO928资讯网——每日最新资讯28at.com

好吧原谅你了,这次不准再忘了,下面跟我一起来看看这究竟是什么原因。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

四、线程池工作流程

这里放一下线程池的工作流程。bO928资讯网——每日最新资讯28at.com

面试官:线程池核心线程设置为0时任务执行流程怎么样的bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

知道了线程池的工作流程之后,在上述代码中,哪怕增加了最大线程池的数量,最终子任务也并不会执行到,我们可以打印一下当前线程池的状态进行辅助观察。(上述代码的printThreadPoolStatus()方法会进行线程池当前状态的打印)bO928资讯网——每日最新资讯28at.com

调用一下GET http://localhost:8080/test/info方法查看线程池当前的状态。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

可以看到队列中存在3个任务在排队,等待线程池分配线程执行任务。这也就是修改了最大线程池数量未生效的原因,因为还有一个无界队列。bO928资讯网——每日最新资讯28at.com

当然如果任务一直增加,队列中任务数量越来越多,达到服务器的瓶颈,就会发生OOM了。(阿里开发规范中不推荐使用无界队列的原因)bO928资讯网——每日最新资讯28at.com

五、修改核心线程数量

那我们直接修改核心线程数量吧,核心线程超过任务数量?bO928资讯网——每日最新资讯28at.com

回答:不行。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

对于我们上面的例子来说,增加核心线程数量,拥有可以执行子任务的线程,确实可以解决当下场景。bO928资讯网——每日最新资讯28at.com

但是当并发量上来之后,或者说线程池的线程都被父线程所占用时,依旧会发现子任务无法获得线程执行。bO928资讯网——每日最新资讯28at.com

此处我们修改核心线程为10执行看一下输出结果。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

通过修改核心线程数量,解决了子任务在队列中堆积的问题。bO928资讯网——每日最新资讯28at.com

所以通过上述代码,大家应该知道死锁是怎么发生的了吧,这里我总结一下。bO928资讯网——每日最新资讯28at.com

六、小结

当核心线程为1,最大线程为1,使用无界队列。父任务在线程中等待子任务完成的通知,子任务在线程池的任务队列中等待线程池调度线程资源。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

当核心线程为1,最大线程为n,使用无界队列。最大线程设置n与设置1没有区别,除非使用的队列不同,只要是使用的无界队列,当资源耗尽之时,就是服务崩溃的时候。此时后面新的父任务到来时,也只会在任务队列中继续堆积。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

当核心线程为n,最大线程为n,使用无界队列。核心线程设置为n,意味着父线程大概率是可以执行的,创建的子任务在任务队列中排队执行。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

当并发量上来,或者核心线程都被父任务所占据之后,线程池调用就变成了如下场景,所有的任务都被堆积在任务队列当中:bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

核心线程全是父任务,后面创建的任务也都在任务队列堆积,最终达到服务器瓶颈系统OOM。bO928资讯网——每日最新资讯28at.com

七、最终解决方案

通过上述代码示例,死锁的根本原因在于,父任务会创建多个子任务,并等待子任务执行结束,而父子任务都是使用的同一个线程池,当线程池中执行线程都是父任务时,所有的子任务又都在任务队列中等待执行,所以这样就会发生死锁。bO928资讯网——每日最新资讯28at.com

核心线程永远不会释放,从而造成任务队列不断堆积,直到OOM。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

所以解决方案就是,隔离线程池。bO928资讯网——每日最新资讯28at.com

不同的业务使用不同的线程池,使用一个新的线程池处理子任务,这样就可以避免死锁的发生了。bO928资讯网——每日最新资讯28at.com

修改之后的代码如下。bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

bO928资讯网——每日最新资讯28at.com

通过查看日志输出可以发现,线程池隔离之后,哪怕核心线程设置为1,也是可以正常执行业务逻辑的,任务队列中也没有堆积任务。bO928资讯网——每日最新资讯28at.com

八、总结

通过上面的 Demo 复现以及解决方案,在工作中优化建议如下:bO928资讯网——每日最新资讯28at.com

  • 禁止使用Executors创建自定义线程池。使用ThreadPoolExecutor创建线程池时,注意每个参数的含义,规避资源耗尽的风险。
  • 线程池使用有界队列,避免使用无界队列。
  • 对于父子任务的场景,可以使用线程池或者 MQ。使用有界队列之后,制定合理的拒绝策略,拒绝策略可以考虑 MQ 做重试。
  • 不同业务使用不同的线程池,禁止父子任务使用相同的线程池。

本文链接:http://www.28at.com/showinfo-26-112764-0.html不同业务使用同一个线程池发生死锁

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Python必知必会:15个令人相见恨晚的Python字符串格式化技巧!

下一篇: 玩转文件权限:Python 的七个权限操作实战

标签:
  • 热门焦点
  • K60至尊版刚预热 一加Ace2 Pro正面硬刚

    Redmi这边刚如火如荼的宣传了K60 Ultra的各种技术和硬件配置,作为竞品的一加也坐不住了。一加中国区总裁李杰发布了两条微博,表示在自家的一加Ace2上早就已经采用了和PixelWo
  • 6月iOS设备好评榜:第一蝉联榜首近一年

    作为安兔兔各种榜单里变化最小的那个,2023年6月的iOS好评榜和上个月相比没有任何排名上的变化,仅仅是部分设备好评率的下降,长年累月的用户评价和逐渐退出市场的老款机器让这
  • 0糖0卡0脂 旭日森林仙草乌龙茶优惠:15瓶到手29元

    旭日森林无糖仙草乌龙茶510ml*15瓶平时要卖为79.9元,今日下单领取50元优惠券,到手价为29.9元。产品规格:0糖0卡0脂,添加草本仙草汁,清凉爽口,富含茶多酚,保留
  • 之家push系统迭代之路

    前言在这个信息爆炸的互联网时代,能够及时准确获取信息是当今社会要解决的关键问题之一。随着之家用户体量和内容规模的不断增大,传统的靠"主动拉"获取信息的方式已不能满足用
  • JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • 微软邀请 Microsoft 365 商业用户,测试视频编辑器 Clipchamp

    8 月 1 日消息,微软近日宣布即将面向 Microsoft 365 商业用户,开放 Clipchamp 应用,邀请用户通过该应用来编辑视频。微软于 2021 年收购 Clipchamp,随后开始逐步整合到 Microsof
  • 猿辅导与新东方的两种“归途”

    作者|卓心月 出品|零态LT(ID:LingTai_LT)如何成为一家伟大企业?答案一定是对“势”的把握,这其中最关键的当属对企业战略的制定,且能够站在未来看现在,即使这其中的
  • 三星折叠屏手机去年销售近1000万台 今年目标定为1500万

    7月29日消息,三星率先发力可折叠手机市场,在全球市场已经取得了非常亮眼的成绩,接下来会进一步巩固和扩大这一优势。三星在推出Galaxy Z Flip5和Galax
  • 2299元起!iQOO Pad开启预售:性能最强天玑平板

    5月23日,iQOO如期举行了新品发布会,除了首发安卓最强旗舰处理器的iQOO Neo8系列新机外,还在发布会上推出了旗下首款平板电脑——iQOO Pad,其搭载了天玑
Top