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).