Tushar Goel wrote:But i want to know why problem is coming with first option and which one is more elegant to use.
Hi Tushar,
I've been trying to work on your problem for my own learning. Following is what I think is the case.
An uncaught exception handler is not really the same thing as any other catch block. A catch block catches an exception and prevents the thread that threw the exception from terminating if the exception is successfully caught, i.e if the catch block does not result in another exception being thrown. An uncaught exception handler on the other hand is just a facility provided by the Thread class to enable the thread to do additional things before it terminates. Those additional things could be anything - like for example, sending an email to an admin, logging, starting a new Thread -- it really depends on your use case.
In case of worker threads like configurations, the worker thread has no idea of what kind of tasks it is going to run. Some tasks can be nicely coded, but the worker thread has no way of knowing that. So if a worker thread is supposed to execute say 10 tasks, and say task number 5 throws an uncaught RuntimeException, it could terminate the worker thread. This is not what you'd want. This is one of the cases where the uncaught exception handlers come in handy. I could have the uncaught exception handler start another worker thread to execute the remaining tasks. But this wouldn't happen just by implementing the Thread.UncaughtExceptionHandler interface and coding the uncaughtException method to just log the exception. Unlike a catch block, an uncaught exception handler does not prevent the original thread from terminating.
The JLS says the following about the UncaughtExceptionHandlers.
JLS wrote:During the process of throwing an exception, the Java Virtual Machine abruptly completes, one by one, any expressions, statements, method and constructor invocations, initializers, and field initialization expressions that have begun but not completed execution in the current thread. This process continues until a handler is found that indicates that it handles that particular exception by naming the class of the exception or a superclass of the class of the exception (§11.2). If no such handler is found, then the exception may be handled by one of a hierarchy of uncaught exception handlers (§11.3) - thus every effort is made to avoid letting an exception go unhandled.
JLS wrote:If no catch clause that can handle an exception can be found, then the current thread (the thread that encountered the exception) is terminated. Before termination, all finally clauses are executed and the uncaught exception is handled according to the following rules:
If the current thread has an uncaught exception handler set, then that handler is executed.
Otherwise, the method uncaughtException is invoked for the ThreadGroup that is the parent of the current thread. If the ThreadGroup and its parent ThreadGroups do not override uncaughtException, then the default handler's uncaughtException method is invoked.
Let us consider an example. I have a Task class as follows.
Following is my worker thread's implementation. MyRunner is a Runnable that executes tasks in a list within its run method.
If I run the MyRunner class with the commented part as commented, I get the following output.
Thread-0
Thread-0 is running task number 0
Exception in thread "Thread-0" java.lang.RuntimeException: Some stupid RE
at threadandsynchronization.Task.execute(Task.java:28)
at threadandsynchronization.MyRunner.run(MyRunner.java:36)
at java.lang.Thread.run(Unknown Source)
So an exception in the 1st task has terminated my worker and hence tasks 1 till 9 could not run. Obviously if the Task class had a catch-all, my worker thread would not get terminated, but a worker thread does not know if the task is a well planned task. It should prepare for failures in the called code.
Now if I uncomment the UnCaughtExceptionHandler parts, I get the following output.
Thread-0
Thread-0 is running task number 0
Uncaught Exception received. Recieved error on Thread-0 thread. Some stupid RE
Thread-1
Thread-1 is running task number 1
After catch in the task 1
Thread-1is done executing task 1
Thread-1
Thread-1 is running task number 2
After catch in the task 2
Thread-1is done executing task 2
Thread-1
Thread-1 is running task number 3
After catch in the task 3
Thread-1is done executing task 3
Thread-1
Thread-1 is running task number 4
After catch in the task 4
Thread-1is done executing task 4
Thread-1
Thread-1 is running task number 5
Uncaught Exception received. Recieved error on Thread-1 thread. Some stupid RE
Thread-2
Thread-2 is running task number 6
After catch in the task 6
Thread-2is done executing task 6
Thread-2
Thread-2 is running task number 7
After catch in the task 7
Thread-2is done executing task 7
Thread-2
Thread-2 is running task number 8
After catch in the task 8
Thread-2is done executing task 8
Thread-2
Thread-2 is running task number 9
After catch in the task 9
Thread-2is done executing task 9
After all tasks have started
In your first case, you are just logging the exception as a part of the Uncaught exception handler. This will not prevent the thread that is calling the startServer method from terminating.
Obviously you need to analyze why you are getting the StringIndexOutOfBoundException. That is the real problem you need to solve. But to think that an uncaught exception handler that just logs an exception can catch an exception just like a catch block does would be wrong in my opinion.
To answer the question, which of the two things are better, I think that an uncaught exception handler and a catch-all block in the task class are not mutually exclusive. Worker threads execute tasks generally through an abstraction and since tasks are unknown kind of things to worker threads, uncaught exception handlers are good regardless of whether the task has a catch-all block.
I don't know if a catch-all block in the Task class is a good idea. Obviously the catch-all block would make sure the failure condition will not cause the invoking thread to terminate, which is what well planned tasks do. But you don't require a catch-all to catch ( and handle in the correct way ) all the likely failure conditions. Also catch-all's are risky. I mean you never know for how long you are still using the corrupted data till you see a failure later. But that's just one of the things ( significant things ) and it really depends on your implementation and the possibilities with your use case.