1

My consumer doesn't work the way I expect it to. Below is an sscce of what happens in my real program.

  • Expected:
    1. Print In finally!
    2. Print About to print stacktrace
    3. Print a NullPointerException stacktrace.
  • Actual:
    1. Print In finally!
    2. Hang, in sun.misc.Unsafe

Program:

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class ThreadTest implements Runnable {
    public static void main(String... args) {
        ExecutorService service = Executors.newSingleThreadExecutor(new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread newThread = new Thread(r);
                        newThread.setUncaughtExceptionHandler(new MyExceptionHandler());
                        return newThread;
                    }
                });
        service.submit(new ThreadTest());
    }

    private static class MyExceptionHandler implements UncaughtExceptionHandler {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("About to print stacktrace");
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        Object foo = null;
        try {
            while(!Thread.interrupted()) {
                Thread.sleep(1000);
                System.out.println(foo.toString());
                System.out.println("After npe!");
            }
        } catch(InterruptedException e) {

        } finally {
            System.out.println("In finally!");
        }
    }
}
durron597
  • 31,968
  • 17
  • 99
  • 158

1 Answers1

2

Runnables run inside an Executor don't really throw exceptions which will hit the thread's uncaught exception handler. Instead, the Runnable is wrapped with code which catches Throwable. This is so that a Future can return the exception that was thrown from the task.

as @Gray noted in the comments below, your program is "hanging" because the thread pool thread is keeping the program from exiting. your runnable has completed and the thread pool thread is just waiting for a new task. if you shutdown the thread pool, your program will complete normally (or make the thread pool threads daemon).

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
  • Why does it hang, though? – durron597 Sep 27 '13 at 20:46
  • 1
    It hangs because you've not shutdown your executor service @durron597. – Gray Sep 27 '13 at 20:47
  • You probably should use a `Callable` that will throw the NPE once you call future.get(). – Gray Sep 27 '13 at 20:47
  • 1
    @Gray - the OP doesn't need to use Callable to get that to work, just hang on to the returned Future. – jtahlborn Sep 27 '13 at 20:50
  • True @jtahlborn. I instinctively move to `Callable` if I want the throw because it forces the catch but you are right when it's a `RuntimeException`. – Gray Sep 27 '13 at 20:52
  • Well it turns out that for my real application, the thing that makes the most sense is to add a `catch (Throwable t)` and handle it there. But this answer got me on the right track, thanks! – durron597 Sep 27 '13 at 21:12
  • Also I briefly considered using [`Executors.callable(Runnable task)`](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#callable%28java.lang.Runnable%29) before going this route, you may want to edit that into your post as well – durron597 Sep 27 '13 at 21:15