Thats right! Motherfuck this service.
Deep hidden in the javadoc of this magnificent class is this gem “If any execution of the task encounters an exception, subsequent executions are suppressed.”. In other words, if your runnable task has any fuckups, your task will no longer be run. What sucks about this, is there is no clear indication that there was a fuckup in the task. No warning, just silenty the task gets canceled leading you to say: “Dude! where my task!?”
Lets use this example:
import java.util.concurrent.Executors;
public class BadAssTask implements Runnable {
@Override
public void run() {
System.out.println("Sleeping ...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Throwing ... ");
throw new RuntimeException("bad ass!");
}
public static void main(String[] args) {
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new BadAssTask(), 1, 1, TimeUnit.SECONDS);
}
}
And now comment in lines 14 & 15 and notice that it only runs once and gives no indication that the executor stopped running your task.
Ever wonder why your shit was not running… well, now you know.
But there are 2 ways to solve this:
1. try/catch that fucker!
Thats right. Put a try big ass try/catch around your entire runnable and deal with any errors. You should be doing this anyways!
2. Extened the implenentation of the ScheduledExecutorService
Thats right. Extend that fucker. Extend it to wrap all given runnables with your own runnable that has a try catch around the run method. And then log that shit in case of errors. And finally, rethrow that bitch so that existing bahavior is preserved. This is the more generic solution. Here is the code for such an Executor:
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Fuck that East Coast shit!
*
* @author srasul
*
*/
public class WestCoastScheduledExecutor extends ScheduledThreadPoolExecutor {
public WestCoastScheduledExecutor(int corePoolSize) {
super(corePoolSize);
}
@Override
public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return super.scheduleAtFixedRate(wrapRunnable(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return super.scheduleWithFixedDelay(wrapRunnable(command), initialDelay, delay, unit);
}
private Runnable wrapRunnable(Runnable command) {
return new LogOnExceptionRunnable(command);
}
private class LogOnExceptionRunnable implements Runnable {
private Runnable theRunnable;
public LogOnExceptionRunnable(Runnable theRunnable) {
super();
this.theRunnable = theRunnable;
}
@Override
public void run() {
try {
theRunnable.run();
} catch (Exception e) {
// LOG IT HERE!!!
System.err.println("error in executing: " + theRunnable + ". It will no longer be run!");
e.printStackTrace();
// and re throw it so that the Executor also gets this error so that it can do what it would
// usually do
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
new WestCoastScheduledExecutor(1).scheduleAtFixedRate(new BadAssTask(), 1, 1, TimeUnit.SECONDS);
}
}
And using this code, you can now see the exact error that was thrown by your task causing it to no longer run.


#1 by Ritesh on March 28th, 2012
Quote
realy awsome dude
#2 by Kristen McIntyre on May 30th, 2012
Quote
You have an excellent post.
#3 by Matt on June 8th, 2012
Quote
Thanks, very helpful!
#4 by Usman Ismail on June 13th, 2012
Quote
So obvious now that you point it out but yeah I have the same code. Don’t think it has caused problems yet but will surely do at some point. What is the license for this code? Any problems with me using it?
#5 by Robert on September 8th, 2012
Quote
good one…I was wondering why my service was not working, thanks.
Robert
#6 by Obe on January 23rd, 2013
Quote
You should better catch(Throwable th) instead of catch(Exception e) since it is also possible that your run method might throw an Error such as memory issues. try it with throw new Error() and you still won’t see any stacktrace….
Error is not an Exception so it won’t be catched.
#7 by Brennen on January 27th, 2013
Quote
Great post, had troubles with this. Hilarious as well as informative.
#8 by Mike Argyriou on February 14th, 2013
Quote
Nice article and ideas but check the hook method ThreadPoolExecutor.afterExecute() … it can be used for checking if an exception happened!
#9 by Arun on February 19th, 2013
Quote
Nice Post
#10 by Brad on April 5th, 2013
Quote
Yeah, it sucks. The best solution I’ve found is to pass a custom thread factory when constructing the Executor:
Executors.newSched….(…, MyThreadFactory)
In addition to the thread factory being able to set an uncaught exception handler, it has the added benefit of being able to name the threads, which is helpful for debugging.
Google’s Guava is useful for this, where the thread factory can be built in the following way:
new ThreadFactoryBuilder()
.setNameFormat(“safethread-%d”)
.setUncaughtExceptionHandler(new MyExHandler())
.build()));
where MyExHandler implements the Thread.UncaughtExceptionHandler intferface and can log any uncaught exceptions so you know what went wrong.
#11 by Bob on April 10th, 2013
Quote
good post – I like your style