I have a runnable that I want to run periodically. On a particular run, I believe the runnable encountered a null pointer, but no exception was shown on the console. After that failed run, it never runs again. I have two questions:
scheduler = Executors.newScheduledThreadPool(1);
MyRunnable mr = new MyRunnable(this.data);
scheduler.scheduleWithFixedDelay(mr, 0, STATUS_SENDER_PERIOD, TimeUnit.MILLISECONDS);
Answering your questions,
1) The reason why you do not see any kind of exception is due to the fact that the FutureTask#setException
called within FutureTask#run
effectively swallows it. In order to be be able to log the exception you should either create a new class the extends the ScheduledThreadPoolExecutor
and override the afterExecute
method like so:
@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();
}
}
Or directly invoke get
on the returned ScheduledFuture
like so:
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) The easiest way of re-running the failed runnable would to do this:
while (true) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
But imho this approach is not the cleanest. Properly coding your Runnable#run
method to handle exception would be a better solution.