的文档scheduleAtFixedRate
并scheduleWithFixedDelay
说:
如果任务的任何执行遇到异常,后续执行将被抑制
假设我的任务是为了做一些网络工作而没有找到主机。任务不会再次执行吗?主机可能会在下一刻重新联机。
假设文档所说的是一个实例RuntimeException
,比如数组索引越界,任务将永远不会再次执行吗?如果我希望他们继续执行怎么办?
的文档scheduleAtFixedRate
并scheduleWithFixedDelay
说:
如果任务的任何执行遇到异常,后续执行将被抑制
假设我的任务是为了做一些网络工作而没有找到主机。任务不会再次执行吗?主机可能会在下一刻重新联机。
假设文档所说的是一个实例RuntimeException
,比如数组索引越界,任务将永远不会再次执行吗?如果我希望他们继续执行怎么办?
任务将永远不会再次执行吗?
这就是“禁止后续处决”的意思,不是吗?
如果我希望他们继续执行怎么办?
不要让RuntimeExceptions
他们Errors
逃脱。
检查由调度程序执行的 Runnable 操作中未捕获的异常。默认情况下,JVM 不会捕获它们并且线程在不被注意的情况下崩溃。
我建议使用 custom ScheduledThreadPoolExecutor
,如下所示:
static class MyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
public MyScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {
super(corePoolSize, threadFactory);
}
@Override
public ScheduledFuture<?> schedule(Runnable command, long delay,TimeUnit unit) {
return super.schedule(new SheduleExceptionCatcher(command), delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay, long period, TimeUnit unit) {
return super.scheduleAtFixedRate(new SheduleExceptionCatcher(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay, long delay, TimeUnit unit) {
return super.scheduleWithFixedDelay(new SheduleExceptionCatcher(command), initialDelay, delay, unit);
}
/** Wrap for Runnable - for error catching */
private static class SheduleExceptionCatcher implements Runnable {
private Runnable task;
public SheduleExceptionCatcher(Runnable task) {
this.task = task;
}
@Override
public void run() {
try {
task.run();
} catch (Throwable e) {
System.err.println("" + e); // or some logger probably
}
}
}
}
并进行一些测试:
public static void main(String[] args) {
new MyScheduledThreadPoolExecutor(2, new PriorityThreadFactory("GeneralSTPool", Thread.NORM_PRIORITY)).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
throw new RuntimeException("Test Error");
}
},3000, 3000, TimeUnit.MILLISECONDS);
while (true){}
}
将打印
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
因此,尽管抛出错误,您的任务仍将永远执行。
当我忘记在内部捕获异常时,不明白崩溃发生在哪里是非常烦人的Runnable
。实际上我不需要忽略所有这些异常,我只需要确保我不会忽视它们。为此,我创建了 CatchyRunnable类,它是一个包装器,用于Runnable
记录异常并在需要时传播它们:
executorService.submit(new CatchyRunnable(new Runnable() {
@Override
public void run() {
throw new RuntimeException("log me");
}
});
您可以通过应用工厂方法模式来使用更简洁的语法,我只是打算与 lambdas 一起使用:
executorService.submit(new CatchyRunnable(() -> {
throw new RuntimeException("log me");
});