UncaughtExceptionHandler初探(1)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、UncaughtExceptionHandler 是什么?
  • 二、使用步骤
    • 1.通过try-catch捕捉子线程的问题
    • 2.非线程池设置
    • 3.线程池的情况下设置UncaughtExceptionHandler
  • 总结


前言

前些天,在网上逛论坛的时候看到 UncaughtExceptionHandler ,貌似从来没用过,所以学习下


一、UncaughtExceptionHandler 是什么?

/**
 * 当线程由于未捕获异常而突然终止时调用的处理程序接口。 
 * 当线程由于未捕获异常即将终止时,Java虚拟机将使用getUncaughtExceptionHandler查询线程的
 * UncaughtExceptionHandler,并调用处理程序的uncaughtException方法,将线程和异常作为参数传递。
 * 如果线程未显式设置其UncaughtExceptionHandler,则其ThreadGroup对象将充当其
 * UncaughtExceptionHandler。
 * 如果ThreadGroup对象对处理异常没有特殊要求,它可以将调用转发给默认的未捕获异常处理程序。
 */
public interface UncaughtExceptionHandler {
    /**
     * 方法,该方法在给定线程由于给定的未捕获异常而终止时调用。 
     * Java虚拟机将忽略此方法引发的任何异常。 
     * 参数: 
     * t–线程 
     * e–异常
     */
    void uncaughtException(Thread t, Throwable e);
 }

这个描述看取来 就是给程序员一个钩子函数,让程序可以感知到线程非正常关闭时的情况,可以打日志 或者 啥操作

二、使用步骤

1.通过try-catch捕捉子线程的问题

public class Test {

    public static void main(String[] args) {
        try {
            Thread thread = new Thread(new Task());
            thread.start();
        } catch (Exception e) {
            System.out.println("==Exception: " + e.getMessage());
        }
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println(1 / 0);
    }
}
输出
Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
	at com.example.demo.config.Task.run(ttt.java:33)
	at java.lang.Thread.run(Thread.java:745)

可以看到,其实catch 并未捕捉到 异常,而子线程的错误 抛出到虚拟机了

2.非线程池设置

通过设置线程的UncaughtExceptionHandler 则可以捕捉到异常

public class Test {
    public static void main(String args[]) {
        Thread thread = new Thread(new Task());
        thread.setUncaughtExceptionHandler(new ExceptionHandlerDemo());
        thread.start();
    }
}

class ExceptionHandlerDemo implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("whp Exception: " + e.getMessage());
    }
}


class Task implements Runnable {
    @Override
    public void run() {
        System.out.println(1 / 0);
    }
}

输出:
whp Exception: / by zero

3.线程池的情况下设置UncaughtExceptionHandler

public class testClass {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolTaskExecutor executorService = buildThreadPoolTaskExecutor();
        //这里注意先是execute ,如果是submit 则有些不同 需要get 才能出现错误
        executorService.execute(() -> run("execute方法"));
    }

    private static void run(String name) {
        String printStr = "【thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name+"】";
        System.out.println(printStr);
        throw new RuntimeException(printStr + ",出现异常");
    }



    private static ThreadPoolTaskExecutor buildThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();
        executorService.setCorePoolSize(5);
        executorService.setMaxPoolSize(5);
        executorService.setQueueCapacity(10);
        executorService.setKeepAliveSeconds(10);
        executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executorService.setThreadFactory(new DefineThreadFactory("小王"));
        executorService.initialize();
        return executorService;
    }

}


import io.netty.util.concurrent.DefaultThreadFactory;

/**
 * 这里图简单 ,继承了一个ThreadFactory实现
 */
public class DefineThreadFactory extends DefaultThreadFactory {


    public DefineThreadFactory(String poolName) {
        super(poolName);
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = super.newThread(r);
        //给生成的线程设置一个错误处理器
        t.setUncaughtExceptionHandler(new ExceptionHandler());
        return t;
    }
}


public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("define==Exception: " + e.getMessage());
    }
}
输出:
09:55:09.844 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService
【thread-name:小王-1-1,执行方式:execute方法】
define==Exception: 【thread-name:小王-1-1,执行方式:execute方法】,出现异常


可以看到 线程池中工作线程 的错误也被捕捉到了


总结

UncaughtExceptionHandler API 提供了一个优雅的方式,让我们可以处理线程的异常错误。

你可能感兴趣的:(多线程)