11

I prefer to have the exception handling logic further up in the call stack, near the main method. I like this approach... However, I created a thread where some of its method calls inside run() may throw exceptions. I would really like to see if there is a way that these exceptions can be thrown back up to the parent thread? The best I could think of is setting a variable inside the object that implements Runnable. This variable is a string that contains the Error Message, which then uses a class loader to correctly re-create the same exception in the parent thread.

What I would like to know, is there a less messy way of getting what I want here? (to be able to make sure that any exception thrown in a child thread is handled with the same exception handling logic as though it was running in the main thread/code re-use).

Zombies
  • 25,039
  • 43
  • 140
  • 225
  • It seems this question is asked a lot here... I would consider closing it but after having read the others a little more this question does ask something different: is using a class loader + saving the exception in the runnable object viable? – Zombies Apr 13 '10 at 17:46
  • Apparently it's not as indicated by Bill K. Thanks. – Zombies Apr 13 '10 at 17:48

3 Answers3

26

You can use an ExecutorService here to submit a callable and receive a Future. At the point you would at the very least want the Exception to be propagated to the invoking thread you would invoke future.get()

future.get() will propogate any exception thrown in the call method to the thread that is invoking future.get(). So if your main thread invokes future.get() then the main thread will see any exceptions thrown.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • 3
    Futures is one of the most under-used features in Java. More than half of the direct thread usage I need can be done safer, easier, and cheaper with Futures. – James Schek Apr 13 '10 at 18:00
  • 1
    @James youre 100% right, even a simple synchronization barrier is much easier with Futures then the more known CountdownLatch and CyclicBarrier – John Vint Apr 13 '10 at 18:01
  • 1
    @JohnVint - Nice Tip. One question - Would the exception be thrown even if future.get() is called after the child thread died (after throwing a runtimeException) – Andy Dufresne May 29 '13 at 12:05
  • 3
    @AndyDufresne Yes. The Future itself buffers the exception propagated from the now dead thread. When you invoke `get` it will check to see if the buffered exception is non-null, and will throw it if it isn't (this applies at least to the current implementation, the doc's don't necessarily say this but I would imagine it would remain constant). – John Vint May 29 '13 at 12:14
4

Catch it at the outer level of your run() method then place the Exception in a variable in your Runnable and have your Runnable indicate that it completed.

The code that started your runnable has to then examine the Runnable to see that the "Exception" object is set and either rethrow it or deal with it.

If you rethrow it, you may want to wrap it in a new exception:

throw new Exception(oldException);

This will give you both stack traces.

(Thanks Taylor L)

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • 1
    I think fillInStackTrace would replace the current stack frame rather than the original stack frame of the exception. I'm not sure that's what you'd want. Perhaps it would be better to wrap the exception with a new one like throw new YourException(originalException). The rest seems fine though. – Taylor Leese Apr 13 '10 at 17:46
4

With Thread.setUncaughtExceptionHandler() you can set an Thread.UncaughtExceptionHandler in your Thread and have a centralized logic of handling exceptions of your threads.

Moreover you can write your own ThreadFactory that will create you threads with preset Thread.UncaughtExceptionHandler.

pajton
  • 15,828
  • 8
  • 54
  • 65
  • 1
    I think my only issue with that is that `Thread.UncaughtExceptionHandler` forces me to handle the exception there, but I want to throw it back up a few stacks towards main(). – Zombies Apr 13 '10 at 17:51