腾讯王卡运营坑之一:web容器优雅停机缓慢

什么叫做优雅停机

通俗点理解(以tomcat为例),优雅停机就是当tomcat收到停机命令时,tomcat会关闭所有入口(表明我已经要停机了,你们别再来请求我了),同时对已经接受的请求继续完成相应的处理逻辑。当所有的用户定义的线程都处理完成,进程内只剩下daemon线程时,机彻底关机,杀死进程。

优雅停机的正确姿势

ps -ef|grep java 找到你需要杀死的pid

 

假如我们要杀死的进程pid为254569,则执行 kill  254569即可。切记千万不能如此操作 kill -9  254569,如此操作后进程马上杀死,同时会造成已经接收的请求不会继续处理,从而造成一些不必要的逻辑错误。

问题回顾

在系统逻辑实现时,为了提高系统吞吐量,程序猿们往往会使用一些多线程技术,来处理一些延时高的、强依赖资源的一些请求(消耗资源比较高的通常是DBio,网络io,文件读写io)。但是在使用时经常忽略了线程的关闭问题,下面就是腾讯王卡在运营过程中发现的问题。

在本地项目停止过程中发现,tomcat在停止时很耗时,甚至停止过程中直接抛出异常,这个现象引起了大家的注意。

我们是这样定位的:

第一:停止tomcat

第二:使用jstack命令查看停机后,还有那些线程在运行

第三:分析打印出来的堆栈信息

在分析jstack打印出来的堆栈信息时,找出和项目相关代码,查看可疑点。

问题分析:

该代码是向线程池提交执行一个逻辑,该逻辑是一个死循环

改进后的代码如:

改进后的方法,没使用线程池提交,直接new一下thread执行即可。那问题来了,那线程池和直接new一个thread执行相同的方法,为啥线程池就不可以,new 一个thread就可以呢?

带着问题,我们分别查看线程的shutdown方法和线程的interrupt。相关代码截图如下

我们先分析一下线程池的shutdown方法。

checkShutdownAccess检查操作权限

advanceRunState关闭线程池

interruptIdleWorkers中断空闲线程

onShutdown取消一些延迟任务

大家请注意interruptIdleWorkers的作用中断空闲线程,而我们的方法是一个死循环,自然不能中断

线程池里面有个方法叫shutdownNow,里面有个方法interruptWorkers,该方法是强制关闭所有线程,不论是空闲还是繁忙。到此我们了解了线程池为什么清理死循环的线程了。

而直接new一个thread之所以可以中断一个死循环的线程,是因为interrupt0这个方法的存在,该方法作用是给线程打个标记(Just to set the interrupt flag),告诉操作系统,该线程可以终止,操作系统会自动中断被标记中断的线程。

问题解方案

最后建议大家,如果确实有业务需要写一个死循环,不中断的处理一些业务,我们建议使用如下两种写法

写法一:

该方法在bean被销毁时,start标志会置为false,从而退出死循环

写法二:

使用interrupted()方法,根据线程的中断状态来退出循环

总而言之,言而总之:线程池不能用于处理死循环逻辑。

 

如分析有误,欢迎大家拍砖

 作者也玩公众号,欢迎关注《JAVA之庖丁解牛》

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值