Channels ▼

Eric Bruno

Dr. Dobb's Bloggers

Uncaught Java Thread Exceptions

February 11, 2013

I recently encountered an issue where a worker thread was terminating quietly in some code I hadn't written, and couldn't really change. In this case, the thread was terminating due to an exception it had encountered. I wanted to robustly know when this thread terminated so that I could log it, and then restart it to continue the processing it was doing. I'll explain how I resolved this, but first, let's examine some code that illustrates the problem:

public class MyApp {
    static int count = 0;
    
    public class MyWorker extends Thread {
        public void run() {
            while ( true ) {
                try {
                    // Do this work every second forever unless interuppted
                    doWork();
                    Thread.sleep(1000);
                }
                catch ( InterruptedException e ) { 
                    return;
                }
            }
        }
        
        private void doWork() {
            // Simulate work that sometimes results in NullPointerException
            StringBuffer sb = new StringBuffer("My Work counter: ");
            if ( count++ >= 5 ) {
                sb = null; //oops!
                count = 0;
            }
            sb.append(count);
            System.out.println(sb.toString());
        }
    }
    
    public MyApp() {
        MyWorker worker = new MyWorker();
        worker.start();
    }
    
    public static void main(String[] args) {
        MyApp te = new MyApp();
    }
}

To summarize, we have a main class, MyApp, with a nested class, MyWorker, which extends Thread. In the run method, a call is made to the doWork method every second forever unless the thread is interrupted. However, the code has a bug, simulated by the creating of a NullPointerException, which is never handled, thus terminating the Thread. The issue is that the application code never really knows that it happens and the periodic processing that the Thread was doing has now ceased.

Thread.UncaughtExceptionHandler

According to the Java API documentation, when a thread is about to terminate due to an uncaught exception, the Java Virtual Machine will query the thread for its UncaughtExceptionHandler using Thread.getUncaughtExceptionHandler() and will invoke the handler's uncaughtException method, passing the thread and the exception as arguments. If a thread has not had its UncaughtExceptionHandler explicitly set, then its ThreadGroup object acts as its UncaughtExceptionHandler. If the ThreadGroup object has no special requirements for dealing with the exception, it can forward the invocation to the default uncaught exception handler.

Java allows you to install a default exception handler for threads, for just this very reason. You have three options in doing so:

  1. You can set it for a specific Thread
  2. You can set it for a ThreadGroup (which means for all Threads in that group)
  3. You can set it VM wide for all Threads regardless

In our example, where the Exception occurs in code we cannot change, we'll need to go with option 3. Doing so is very easy, and allows us to log the Exception that has occurred, get the full stack trace, and then restart the worker Thread since it will have terminated by the time the exception handler is notified. Here is the code modified to install a default exception handler (only the modified code is shown):

public class MyApp {

    ...

    public MyApp() {
        Thread.setDefaultUncaughtExceptionHandler(
                new Thread.UncaughtExceptionHandler() {
                    @Override public void uncaughtException(Thread t, Throwable e) {
                        System.out.println(t.getName()+": "+e);
                        MyWorker worker = new MyWorker();
                        worker.start();
                    }
                });
        
        MyWorker worker = new MyWorker();
        worker.start();
    }
    
    public static void main(String[] args) {
        MyApp te = new MyApp();
    }
}

With this change when the unhanded NullPointerException occurs, the default UncaughtExceptionHandler we installed is invoked, which logs the thread name and the exception, and then restarts the worker thread to continue its processing. Although the original problem of the thread terminating still occurs, at least we now have insight as to when it happens, and can take action. In this example, we simply restart the worker thread to ensure the processing still occurs.

Executing this code now shows the following:

My Work counter: 1
My Work counter: 2
My Work counter: 3
My Work counter: 4
My Work counter: 5
Thread-0: java.lang.NullPointerException
My Work counter: 1
My Work counter: 2
My Work counter: 3
My Work counter: 4
My Work counter: 5
Thread-1: java.lang.NullPointerException
My Work counter: 1
My Work counter: 2
My Work counter: 3
My Work counter: 4
My Work counter: 5
Thread-2: java.lang.NullPointerException
My Work counter: 1
My Work counter: 2
...

This output continues indefinitely, as it was intended.

Alternatively, we can install the uncaught exception handler for just a specific thread. Using our example, since MyWorker extends Thread, we can call its setDefaultUncaughtExceptionHandler() method and install the same handler code, as shown here:

        MyWorker worker = new MyWorker();
        worker.setDefaultUncaughtExceptionHandler(
                new Thread.UncaughtExceptionHandler() {
                    @Override public void uncaughtException(Thread t, Throwable e) {
                        System.out.println(t.getName()+": "+e);
                        MyWorker worker = new MyWorker();
                        worker.start();
                    }
                });
        worker.start();

Perhaps you'll find this useful in your own code, as I have, to help ensure the robust handling of exceptions, especially when it comes to concurrent processing in worker threads.

Happy coding!
-EJB

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Comments:

ubm_techweb_disqus_sso_-b69da22a2b1b6f61b7714c3ed7adbe9d
2014-05-10T03:15:54

Writing threaded code in Java, brings up a variety of places where exceptions may be concealed from the developer.

For starters:
- SwingWorker
- Future/ FutureTask
- ThreadPoolExecutor
- as well as Thread, of course.

See this post for further details & solutions:

http://literatejava.com/thread...


Permalink
ubm_techweb_disqus_sso_-ab4653ec74a7ba01ba51f6b8be9c2466
2013-12-03T08:24:39

To set uncaught exception handler on an individual thread, the method to be used is:

setUncaughtExceptionHandler()

instead of

setDefaultUncaughtExceptionHandler()


Permalink
ubm_techweb_disqus_sso_-2af3b9421e1247b6070781f9ac64c80d
2013-07-19T05:43:36

Nice blog thanks a lot


Permalink
sudhirkk
2013-03-08T17:36:48

Very helpful article, something which will be useful in my coding in the future. The only issue I found was that if we set the default handler for the specific thread (second approach), it will survive the first occurrence of null pointer exception, but the thread spawned from the unCaughtExceptionHandler will not have the handler set at all. You can see below, that it dies in second time.

This is my count: 1
This is my count: 2
This is my count: 3
This is my count: 4
This is my count: 5
This is my count: 6
Thread-0: NEW java.lang.NullPointerException
This is my count: 1
This is my count: 2
This is my count: 3
This is my count: 4
This is my count: 5
This is my count: 6
Exception in thread "Thread-1" java.lang.NullPointerException
at net.sk.thread.MyApp$MyWorker.run(MyApp.java:13)

Permalink
ubm_techweb_disqus_sso_-b772c69b5b83db821a9d2429e5eb5956
2013-03-08T17:20:52

Hi


Permalink
ubm_techweb_disqus_sso_-34be90983c990cf96565f2de97519b66
2013-02-25T16:47:29

Yes, I meant an additional Thread.sleep(1000) in theuncaughtException method. Look forward to your article on RTSJ.
Thank you


Permalink
ubm_techweb_disqus_sso_-06a6faddc430162ab6c827d900667643
2013-02-24T00:21:20

I suppose you mean an additional Thread.sleep(1000) should be placed in the uncaughtException method, in case an exception occurs with every execution of doWork(). Perhaps, but let's remember this is an illustration of how to handle uncaught Thread exceptions. In a future blog post I'll show how you can use the RTSJ and a periodic real time thread to ensure timing cases like this. Thanks for the feedback!


Permalink
ubm_techweb_disqus_sso_-34be90983c990cf96565f2de97519b66
2013-02-20T00:16:03

To strictly enforce that doWork() is not done or started more than once a second, the Thread.sleep(1000) should be put in the uncaughtException method before worker.start()


Permalink
AndrewBinstock
2013-02-19T04:43:27

Eric Bruno was on the road and asked if I would post this response to my comment:

"Ah, yes. That's correct.To make it truly periodic, you would have to take the time spent processing, subtract it from 1000 milliseconds, and sleep for only the remainder. And that's if the processing takes less than one second to complete, of course. Even that wouldn't be totally accurate with Java SE on a general purpose OS, but it would be better :-) The RTSJ and its implementations have support for a truly periodic real-time thread, which uses a precision timer to ensure your thread begins processing precisely on the time interval you set, and handles the cases where you overrun your processing time budget."


Permalink
AndrewBinstock
2013-02-14T07:15:01

Nice reminder. Thank you! While it's not your point, I don't believe doWork() followed by Thread.sleep(1000) means that doWork() will be done once a second. All you can say, I believe, is that it will never be done more than once a second.


Permalink


Video