一、业务表现
在业务容器中,存在如下三个进程:
- JAVA应用进程
- OBProxy进程
- Agent进程
其中Agent进程会启动一个守护线程,定时检查OBproxy进程的状态,如果OBproxy进程挂了,会重新拉起该进程。
现象
业务容器发生OOM,linux OOM killer主动kill掉了OBProxy进程。
Agent的守护线程未按照预期拉起OBproxy进程。
对应Agent简化版代码如下:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(() -> {
try {
if (obProxyProcessDown) {
pullObProxyProcess();
}
} catch (Exception e) {
//LOG
}
}, 1, 1, TimeUnit.SECONDS);
使用ScheduledExecutorService#scheduleWithFixedDelay定时检查OBproxy进程状态,在OBproxy进程挂掉的情况下主动拉起。
二、原因
如上简化代码,ScheduledExecutorService#scheduleWithFixedDelay里定时任务Task#catch的异常类型是Exception,但是系统OOM那会,抛出的是OOM Error异常,Error > Exception,没Catch住,导致ScheduledExecutorService线程池里的后续任务不执行。
三、复现![在这里插入图片描述](https://img-blog.csdnimg.cn/20210319172142701.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d0X2JldHRlcg==,size_16,color_FFFFFF,t_70)
OOM后,后续的打印动作并未执行。
四、分析![在这里插入图片描述](https://img-blog.csdnimg.cn/2021031917293122.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d0X2JldHRlcg==,size_16,color_FFFFFF,t_70)
定时任务执行异常,上面的java.util.concurrent.FutureTask#runAndReset返回false,导致后续的reExecutePeriodic未执行,定时任务没加入到BlockingQueue中,表现就是:后续定时任务不会执行。
具体可以参考:任务异常导致线程池中的线程变为waiting状态