

简介
在上篇博文中提到了ScheduledThreadPoolExecutor的一个坑:异常信息会丢失,任务不再继续被调度:
Java避坑指南:ScheduledThreadPoolExecutor避坑
下面我们以源码的形式分析这种情况。
ScheduledThreadPoolExecutor异常信息会丢失,任务不再继续被调度的源码分析
当我们提交周期性调度的任务时,会先把任务存储到延迟队列DelayedWorkQueue中,以方法:
ScheduledThreadPoolExecutor#scheduleAtFixedRate为例:


当线程池中的核心线程从队列中获取任务执行时:
ScheduledThreadPoolExecutor.ScheduledFutureTask#run
任务是周期性执行,代码逻辑走红色框内,任务执行并重置逻辑:super.runAndReset(),
,如果super.runAndReset()执行成功,才会更新任务的下次执行时间,并把任务入队,等待下次调度执行。如果super.runAndReset()失败,则不会再次调度此任务。
我们看一下如果被调度的任务抛出异常,super.runAndReset()返回true还是fals:



异常发生后,会保存异常,不再抛出,不主动调用Future#get(),异常信息会丢失,调度任务一般不会调用Future#get(),所以调度的任务发送异常信息会丢失。
任务发生异常后,super.runAndReset()最后一行,根据任务的执行结果ran与任务的执行状态state判断:ran && s == NEW 结果返回false,即:被周期性调度的任务一旦抛出异常,此任务不会再被调度。
小结
使用ScheduledThreadPoolExecutor来周期性的调度任务时,我们一定不要抛出异常,从而导致异常信息丢失,也导致周期性被调度的任务不再继续被调度执行。