Exception caught in thread

Posted by greenba on Thu, 27 Jan 2022 17:52:24 +0100

Summary: when a normal thread throws an exception, it cannot be caught externally. When such an exception is thrown, the thread will end. The main thread and other threads are not affected at all, and the exception thrown by a thread is completely unaware (that is, the exception cannot be caught at all).

Solution: add an UncaughtExceptionHandler for the thread, implement the UncaughtExceptionHandler interface, rewrite the uncaughtException method, and catch exceptions in the method.

Case:

public class ExceptionThread2 implements Runnable {
 
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run() by" + t);
        System.out.println("eh=" + t.getUncaughtExceptionHandler());
        throw new RuntimeException("Throw runtime exception");
    }
}

Operation results:

What should I do
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: This thread does such a thing and throws a runtime exception
    at ExceptionThread.run(ExceptionThread.java:8)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)

From the running results, we can see that this exception is not caught in the main thread, that is

  System.out.println("can you catch exceptions?");

It will never be implemented.

The question is, what should we do if we need to catch the unchecked exception of its thread? After Java se5, we can solve this problem through the Executor. To solve this problem, we need to modify the way the Executor generates threads. Thread.UncaughtExceptionHandler is a new interface in Java se5, which allows us to add an exception handler on each thread object. (UncaughtExceptionHandler). Thread.UncaughtExceptionHandler. The uncaughtexception () method is called when the thread is facing death due to an uncapped exception.

The following example simply demonstrates how to use UncaughtExceptionHandler

public class ExceptionThread2 implements Runnable {
 
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run() by" + t);
        System.out.println("eh=" + t.getUncaughtExceptionHandler());
        throw new RuntimeException("Throw runtime exception");
    }
}
import java.lang.Thread.UncaughtExceptionHandler;

/**
 * Used to catch exceptions --- uncheckedException is caught
 * 
 * @author February30th
 * 
 */
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("Exception caught:" + e);
    }

}
import java.util.concurrent.ThreadFactory;

public class HandlerThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println("Create a new thread");
        Thread t = new Thread(r);
        t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        System.out.println("eh121 = " + t.getUncaughtExceptionHandler());
        return t;
    }

}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ThreadExceptionTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //There are three ways to execute threads.
        //The first is in the ordinary way. This is an exception that can be caught
        Thread t = new Thread(new ExceptionThread2());
        t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        t.start();
        //The second method is based on the ready-made pool and directly based on the thread method. At this time, exceptions cannot be caught. Why? Because a thread is created in the following code and the exception handler is set,
        //However, a new Thread object will be reset in our Thread pool, and this Thread object does not have any exception handlers set. In other words, we do this to threads outside the Thread pool
        //Any operation is useless
        ExecutorService exec1 = Executors.newCachedThreadPool();
        Runnable runnable = new ExceptionThread2();
        Thread t1 = new Thread(runnable);
        t1.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        exec1.execute(runnable);
        
        //The third case is the same as the thread pool. However, through the ThreadFactory mode, some thread controls will be made in the ThreadFactory, and the exception handler can be set
        //Exceptions can be caught at this time.
        ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
        exec.execute(new ExceptionThread2());
        
    }

}

Operation results:

Create a new thread
eh121 = MyUnchecckedExceptionhandler@1b8e059
run() byThread[Thread-0,5,main]
eh=MyUnchecckedExceptionhandler@1b8e059
 Exception caught: java.lang.RuntimeException: Throw runtime exception

As can be seen from the above running results, uncaught exceptions are caught through uncaughtException.

According to the above example, we can set the processors one by one according to the specific situation. However, if we know that we will use the same exception handler everywhere in the code, a simpler way is to set a static field in the Thread class and set this handler as the default uncapped exception handler. Take the following example:

Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
        exec.execute(new ExceptionThread2());

This default handler is called only when there is no non default exception handler in the thread. At run time, the system will check whether the thread has its own exception handler. If not, check whether the corresponding thread group has a dedicated exception handler. If not, call the default exception handler.

Topics: Multithreading