Tuesday, March 13, 2007

New in Java 5 - Thread.UncaughtExceptionHandler

I was working on a threading issue recently and found an incredibly useful Java 5 addition: the UncaughtExceptionHandler.

Objects of this type can handle uncaught exceptions within threads… so if you’re programming in Swing, you can give your EDT thread and your worker thread an UncaughtExceptionHandler. The benefits of this is it removes the possibility of having an exception occur on a thread you have no control over, and then having a stack trace print to the Java console while your app fails silently. It also avoids having to wrap code in try{…}catch(Throwable){…} blocks. This seriously improves your app’s behavior and the code readability.

Code bases pre-Java 5 are probably using hand-rolled ThreadPool objects. If you are using a thread pool then you should be using the Java 5 executor services for a number of reasons. The added benefit in this case is that you can define a ThreadFactory for your executor service… and within your ThreadFactory set an UncaughtExceptionHandler (and set threads to daemon, etc.). Viola! No more try{…}catch(Throwable t){…} blocks!

Beyond this, there is also a static method on Thread called setDefaultUncaughtExceptionHandler. This method sets a default UncaughtExceptionHandler for the entire classloader. This may not be applicable to web development, but for some desktop applications you might have one global error handler that cleanly shuts down the system on an error (an extremely-unrobust system by design). My team is now setting a default uncaught exception handler at startup and removing much of our error handling code. Anything that catches an error and shuts down the system can now be deleted (or wrapped in a RuntimeException), and all the dependencies on an error handling object can be removed.

There is one big caveat to this that I discovered in testing: there is no guarantee that a thrown RuntimeException will be raised up all the way to the default uncaught exception handler. Each Thread can have its own handler, and each ThreadPool can have its own. Uncaught exceptions are delegated up the chain of responsibility, and once caught not elevated further. So if you don’t have complete control over your thread then someone could install their own handler and yours won’t be called. Also, many 3rd party libraries have catch(Exception e) statements that will also prevent your exception from being raised all the way up to the default handler. So it is by no means safe to blindly replace all your error handling code with checked exceptions wrapped in unchecked exceptions. Analysis (or simply testing) is needed to determine when it is safe to rely on the default handler.

This was a very important discovery for me! Go check it out!

3 comments:

Unknown said...

I was having a strange problem regarding Thread which made me confused. Though i have put my code inside try{}catch(Exception e){} in run() method but thread dies without executing the catch block. I was googling if there is some help. Now I put UncaughtExceptionHandler which suppose to log the error when thread crashes next time.

Thank you to share your experinece.

Hamlet D'Arcy said...

Maybe try catching Throwable instead.

Unknown said...

yeah, i also did so. At the upper layer (inside run()) i catch Throwable but i noticed thread disappeared once. Note that i'm using hibernate 3.2 in jdk 6. I suspect hibernate is somewhere eating(!) the thread.

After enabling UncaughtExceptionHandler to get error log, it didn't crash. I will update here if get log.

Thanks for your comment.