I have a ScheduledThreadPoolExecutor that seems to be eating Exceptions. I want my executor service to notify me if a submitted Runnable throws an exception.
For ex
You can subclass ScheduledThreadPoolExecutor and override the afterExecute method to handle exceptions and errors for any kind of Runnable that you submit.
Warning: This method is not applicable to scheduled thread pool executors. This answer has been undeleted for its relevance to other thread pool executors. See Willi's answer.
Override the ThreadFactory
to give Threads an UncaughtExceptionHandler:
ThreadPoolExecutor exec = new ThreadPoolExecutor...;
exec.setThreadFactory(new ExceptionCatchingThreadFactory(exec.getThreadFactory()));
//go on to submit tasks...
private static class ExceptionCatchingThreadFactory implements ThreadFactory {
private final ThreadFactory delegate;
private ExceptionCatchingThreadFactory(ThreadFactory delegate) {
this.delegate = delegate;
}
public Thread newThread(final Runnable r) {
Thread t = delegate.newThread(r);
t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace(); //replace with your handling logic.
}
});
return t;
}
}
You could also use a ThreadPoolTaskScheduler
from the Spring Framework, which exposes a method to set an error handler and does all the wrapping for you. The default behavior depends on the type of task:
If the provided ErrorHandler
is not null, it will be used. Otherwise, repeating tasks will have errors suppressed by default whereas one-shot tasks will have errors propagated by default since those errors may be expected through the returned Future
. In both cases, the errors will be logged.
If you only want to use the wrapping part and not the TaskScheduler
you can use
TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask)
which the TaskScheduler
uses internally.
Consider adding a static event in your ScheduledThreadPoolExecutor class that any of your tasks can call if an exception is thrown. That way, you can leverage that event to capture and handle the exceptions that occur within your threads.
I wrote a small post about this problem a while ago. You have two options:
UncaughtExceptionHandler
you wrap each submitted runnable into a runnable of your own which executes (calls run
) the real runnable inside a try-catch-block.EDIT
As pointed out by Mark, it's important to wrap the Runnable
passed to ScheduledExecutorService
instead of the one passed to the ThreadFactory
.
You can use the get()
method from the Future
you're getting by calling scheduleAtFixedRate()
. It will throw an ExecutionException
if an exeception occurred during the thread execution.