I have an application and need to code a custom global uncaught exception handler. I've read all the stackoverflow threads and each one of them is just missing a clear and simple example of how this is to be implemented.
Consider this simple following example:
public static void log(String msg) throws Exception {
String logPath = "/application/logs/java.log";
Calendar c = new GregorianCalendar();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String now = format.format(c.getTime());
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logPath, true)));
out.println(now + " " + msg);
out.close();
}
It throws a standard exception which is just a standard output. How do I implement my own exception which overrides the standard one by something simple as outputing the error into a log file? Obviously the actual application is much larger and we're talking about uncaught exceptions, which is why try/catch blocks is not the option.
UPDATE: If you could please answer with a very clear full example, because I found dozens of examples like the one #RamonBoza provided, yet I have no idea how to implement them, which is what this question is all about.
UPDATE2: So I've tried to test the only example in the answer below, it obviously doesn't work. I've created a new class file "MyRunnable" and pasted the code in it:
package mypackage;
Thread t = new Thread(new MyRunnable());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error(t + " throws exception: " + e);
}
});
t.start();
//outside that class
class MyRunnable implements Runnable(){
public void run(){
throw new RuntimeException("hey you!");
}
}
Needless to say I get a bunch of errors with this. How can something be outside of class anyway?
UPDATE3: This is the solution that finally works:
package mypackage;
public class MyClass {
public static void main(String[] args) throws Exception {
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stacktrace = sw.toString();
System.out.println(stacktrace);
}
});
//main method code
}
//Rest of the methods here
}
You can set UncaughtExceptionHandler for the thread controlling the code above:
// t is the parent code thread
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error(t + " throws exception: " + e);
}
});
Java docs for UncaughtExceptionHandler -
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
the setUncaughtExceptionHandler is commonly used to free memory or kill threads that the system will not be able to kill, and perhaps, remain zombie.
A real example:
Thread t = new Thread(new MyRunnable());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error(t + " throws exception: " + e);
}
});
t.start();
//outside that class
class MyRunnable implements Runnable(){
public void run(){
throw new RuntimeException("hey you!");
}
}
You can use UncaughtExceptionHandler to handle the exception those causes a thread to terminate abruptly.
Java doc for UncaughtExceptionHandler -
Interface for handlers invoked when a Thread abruptly terminates due
to an uncaught exception. 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
You need to implement this interface and set your implementation of UncaughtExceptionHandler for a thread by using method setUncaughtExceptionHandler.
There are two ways you can do this -
setUncaughtExceptionHandler
setDefaultUncaughtExceptionHandler
1) setUncaughtExceptionHandler - This will be a thread specific exception handler. So in case this thread gets terminated by some unhandled exception, this handler will be used.
2) setDefaultUncaughtExceptionHandler - This will be a default exception handler in case there is no specific uncaught exception handler for a thread.
Example -
class MyExceptionHandler implements UncaughtExceptionHandler{
#Override
public void uncaughtException(Thread arg0, Throwable arg1) {
System.out.println("[DEFAULT EXCEPTION HANDLER] Caught some exception");
}
}
class MyThread extends Thread{
public MyThread() {
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("[THREAD SPECIFIC] My exception handler");
}
});
}
public void run(){
throw new RuntimeException();
}
}
public class Test {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
new MyThread().start();
// current thread does not have a thread specific exception handler
throw new RuntimeException();
}
}
You can try setting your own uncaught Exception handler, however I strongly advise against it. If your application has parts that can potentially break and if that exception is then not properly handled at the location where your code breaks, your entire program will malfunction frequently.
Related
I notice, in this javadoc, https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.UncaughtExceptionHandler.html
that an UncaughtExceptionHandler is used for when an exception occurs but is not caught. But, will that thread fail quietly? I guess so, because it is going about its business asynchronously, but I'm investigating a related issue with one of our processes, and am surprised at only being aware of this now, 10+ years into my career.
The thread will fail quietly :)
More than a decade ago a ran into a similar problem. The performance of a system started to degrade over time. Eventually, I identified the cause: an exception was thrown in a worker thread in some custom thread pool and the worker thread was terminated. So over time, the number of live threads in the thread pool started to decrease and performance dropped.
The problem was hidden by the fact that there was no logging of the exception.
[edit]
My answer above is not correct. This is demonstrated in the below example:
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
public void run(){
throw new RuntimeException();
}
};
t.start();
TimeUnit.SECONDS.sleep(10);
System.out.println("done");
}
}
When the code is run, the following output is shown:
Exception in thread "Thread-0" java.lang.RuntimeException
at Main$1.run(Main.java:8)
done
So the exception is Logged.
Based on #pveentjar's updated answer I ran the following code:
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
public void run() {
throw new RuntimeException("purposeful!");
}
};
t.setUncaughtExceptionHandler((thread, throwable) -> System.out.println("uncaught: " + throwable.getMessage()));
t.start();
TimeUnit.SECONDS.sleep(10);
System.out.println("done");
}
}
, and ascertained that the uncaughtExceptionHandler seems to catch an exception from the thread that uses it, allowing the developer to do what they want with it, but that leaves the question, why bother with that handler, if not to save a system from a silent failure?
output:
uncaught: purposeful!
[a pause of approximately ten seconds]
done
I finally got to the bottom of my specific problem. It was due to shoddy error handling, allowing the thread to fail quietly:
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
public void run() {
try {
//do some stuff
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("done-worker thead");
throw new RuntimeException("purposeful!");
}
};
t.setUncaughtExceptionHandler(
(thread, throwable) -> System.out.println("main thread; uncaugh exception from worker threadt: " + throwable.getMessage()));
t.start();
TimeUnit.SECONDS.sleep(10);
System.out.println("done-main thead");
}
}
In doing "some stuff", the application hit an OutOfMemoryError, which is not, strictly seaking, an Exception. Changing the above to catch(Throwable t), solved it.
A runnable task parses incoming xml file and is invoked from a different class. Sometimes the parsing may fail and throw an exception. The task should be running even when exceptions occur. I tried restarting the same task in a new thread using Uncaught exception handler. But wanted more ideas on that.
Class invoking thread : (invokes thread)
It works fine to restart same task in new thread but probably handling exceptions without leading to a thread exit should be the way
Thread fileProcessThread = new Thread(FileProcessor);
fileProcessorThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread arg0, Throwable arg1)
{
FileProcessor newObject = new FileProcessorTask();
Thread t = new Thread(newObject);
t.start();
}
});
fileProcessor.start();
Task Class :
public void run() {
try {
xmlparser.parse(incomingXmlFile);
}
catch (Exception e) {
Thread.currentThread.getUncaughtExceptionalHandler().uncaughtException(Thread.currentThread(), e);
// this invokes uncaughtException to restart thread ?
}
}
I have a watch service (file directory scan) running, so I need the task all the time, even if thread terminates.
When an exception occurs and call reaches the uncaughtExceptionHandler, the state of the thread is Invalid to start again. So you need to create a new thread and start again.
Code from Thread.start()
// A zero status value corresponds to state "NEW".
if (threadStatus != 0)
throw new IllegalThreadStateException();
However this could easily result in an infinite loop. (exception -> catch -> retry -> exception -> catch ...)
I recommend having a counter which stops the retries after a certain point.
Public class TestClass{
static AtomicInteger counter = new AtomicInteger();
static class MyExceptionHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught");
if (counter.get() == 3) {
System.out.println("Reached Max. retries, exiting");
} else {
counter.incrementAndGet();
new Thread(new MyTask()).start();
}
}
}
static class MyTask implements Runnable {
#Override
public void run() {
try {
Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());
System.out.println("slept");
Thread.sleep(500);
double d = 0 / 0;
} catch (InterruptedException e) {}
}
}
public static void main(String args[]) throws Exception {
Thread thread = new Thread(new MyTask());
thread.start();
}
}
I've used static AtomicInteger but in your implementation probably have a common object which can be passed on from one thread to another and let that object have a counter.
I have the following code that I expect to run successfully to completion but the code fails at the line "fail("this should not be reached");". Can someone please explain why the default uncaught exception handler is not called:
public class UncaughtExceptionTest extends TestCase
implements UncaughtExceptionHandler {
private final List<Throwable> uncaughtExceptions =
new CopyOnWriteArrayList<Throwable>();
class UncaughtExceptionTestInnerClass implements Runnable {
private final ScheduledThreadPoolExecutor executor =
new ScheduledThreadPoolExecutor(1);
private final CountDownLatch latch;
UncaughtExceptionTestInnerClass(CountDownLatch latch) {
this.latch = latch;
executor.schedule(this, 50, TimeUnit.MILLISECONDS);
}
#Override
public void run() {
System.out.println("This is printed");
fail("this should fail");
latch.countDown();
}
}
#Test
public void testUncaughtExceptions() {
Thread.setDefaultUncaughtExceptionHandler(this);
CountDownLatch latch = new CountDownLatch(1);
UncaughtExceptionTestInnerClass testTheInnerClass =
new UncaughtExceptionTestInnerClass(latch);
try {
if (!latch.await(1, TimeUnit.SECONDS)) {
if (uncaughtExceptions.size() > 0) {
Throwable exception = uncaughtExceptions.get(0);
System.out.println("First uncaught exception: " +
exception.getMessage());
}
else {
fail("this should not be reached");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void uncaughtException(Thread t, Throwable e) {
uncaughtExceptions.add(e);
}
}
It has to do with the fact you're using an Executor to run the task. The uncaught exception handler is invoked only if the thread is about to be terminated due to an uncaught exception. If you change your implementation to use a plain thread so that the thread will terminate with the exception, you will see the expected behavior.
Depending on how you submit tasks, the executor thread may catch all Throwables and handle them. Therefore, the thread does not terminate due to these exceptions, and thus the uncaught exception handler does not get involved. For example, ThreadPoolExecutor.execute(Runnable) will trigger the uncaught exception handler. However, ThreadPoolExecutor.submit(Callable) does not. Also, ScheduledThreadPoolExecutor.schedule() does not either (it has to do with their use of FutureTask for implementation).
A better way of accessing unexpected exceptions with an executor service is via Future.
ScheduledThreadPoolExecutor.schedule() takes a Runnable/Callable argument, not Thread. The former don't have runtime exception handlers. Have a try/catch block for a RuntimeException in your run or call method.
I am creating some multi-threaded code, and I have created a JobDispatcher class that creates threads. I want this object to handle any unhandled exceptions in the worker threads, and so I am using
Thread.setUncaughtExceptionHandler(this);
Now, I would like to test this functionality - how can I generate an unhandled exception in the run() method of my worker object?
Just throw any exception.
E.g.:
throw new RuntimeException("Testing unhandled exception processing.");
Complete:
public class RuntimeTest
{
public static void main(String[] a)
{
Thread t = new Thread()
{
public void run()
{
throw new RuntimeException("Testing unhandled exception processing.");
}
};
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
public void uncaughtException(Thread t, Throwable e)
{
System.err.println(t + "; " + e);
}
});
t.start();
}
}
What's the problem with just throwing an exception:
throw new Exception("This should be unhandled");
Inside your run method. And of course, not catching it. It should trigger your handler.
You should throw some unchecked exception. An unchecked exception does not require your code to handle it, and is therefore a good candidate to make all the way down the call stack.
You can choose RuntimeException for example, or even something like AssertionError, if you want to minimize the chances that some part of the code catches the exception and handles it before it reaches your handler.
just add this code and you'll get unhandled exception without lint error:
int i = 1/0;
If I invoke the run() method on a Thread and the run() method throws an uncaught Exception what would be the outcome ?
Who catches this Exception? Does the Exception even get caught?
If there is an exception handler installed for the ThreadGroup, the JVM passes the exception to it. If it's an AWT thread, you can install an event handler for otherwise unhandled exceptions. Otherwise the JVM handles it.
Example of a thread group with a custom handler and how to use it:
public class MyThreadGroup extends ThreadGroup {
public MyThreadGroup() {
super("My Thread Group");
}
public void uncaughtException(Thread t, Throwable ex) {
// Handle exception
}
}
Thread t = new Thread(new MyThreadGroup(), "My Thread") { ... };
t.start();
Example of using an AWT exception handler:
public class MyExceptionHandler {
public void handle(Throwable ex) {
// Handle exception
}
public void handle(Thread t, Throwable ex) {
// Handle exception
}
}
System.setProperty("sun.awt.exception.handler", MyExceptionHandler.class.getName());
If you've submitted the Runnable to an ExecutorService you can catch the Exception as wrapped inside a ExecutionException. (Highly recommended over simply calling run())
It can if you assign it to a ThreadGroup that implements the uncaughtException(Thread, Throwable) method.