可运行对象中的异常似乎会杀死线程池



>我有一个可运行的,我想定期运行。在特定运行中,我相信可运行对象遇到了空指针,但控制台上没有显示异常。运行失败后,它再也不会运行。我有两个问题:

  1. 如果有空指针,为什么控制台上没有显示
  2. 即使
  3. 特定运行失败,如何让计划任务在将来再次运行?
scheduler = Executors.newScheduledThreadPool(1);
MyRunnable mr = new MyRunnable(this.data);
scheduler.scheduleWithFixedDelay(mr, 0, STATUS_SENDER_PERIOD, TimeUnit.MILLISECONDS);

回答您的问题,

1(您没有看到任何类型的异常的原因是由于在FutureTask#run中调用的FutureTask#setException有效地吞噬了它。为了能够记录异常,您应该创建一个扩展ScheduledThreadPoolExecutor的新类并覆盖afterExecute方法,如下所示:

@Override
protected void afterExecute(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
t = e;
}
}
if (t != null) {
t.printStackTrace();
}
}

或者直接在返回的ScheduledFuture上调用get,如下所示:

var executor = Executors.newSingleThreadScheduledExecutor();
var future = executor.scheduleAtFixedRate(new MyRunnable(null), 1, 1, TimeUnit.SECONDS);
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}

2( 重新运行失败的可运行对象的最简单方法是这样做:

while (true) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}

但恕我直言,这种方法并不是最干净的。正确编码Runnable#run方法以处理异常将是一个更好的解决方案。

最新更新