ScheduledExecutorService 的一个小坑
先看一段代码
@Test
public void test_schedule() throws IOException {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
AtomicInteger integer = new AtomicInteger(0);
executor.scheduleAtFixedRate(() -> {
System.out.println(integer.incrementAndGet());
if (integer.intValue() == 3) {
throw new RuntimeException();
}
}, 0, 1, TimeUnit.SECONDS);
System.in.read();
}执行结果:
1
2
3
执行到第 3 次之后,程序不再输出任何内容,定时任务悄然停止。
两个问题
1. RuntimeException 不会有任何感知
没有 try-catch 打印栈信息,也没有记录日志,整个异常就这么消失了。不要指望 JVM 会自动打印线程里的异常栈——Java 的线程没干这个事。
2. RuntimeException 会导致定时任务永久停止
scheduleAtFixedRate 的官方注释:
If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
即:只要任意一次执行抛出异常,后续所有调度都会被静默取消,且没有任何错误提示。
正确的写法
写在线程中运行的 Runnable,上来先 try-catch 一切:
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
// 业务逻辑
} catch (Throwable t) {
log.error("定时任务执行异常", t);
}
}
}, 0, 1, TimeUnit.SECONDS);注意: 要 catch
Throwable,不能只 catchRuntimeException——非运行时异常同样会让线程静默死掉,而且没有任何感知。
原博客发布日期:2019-03-27