第九章、核心7:线程异常处理(全局异常处理UncaughtExceptionHandler)

  • 线程的未捕获异常UncaughtException应该如何处理?

1、为什么需要UncaughtExceptionHandler?

  • 主线程可以轻松发现异常,子线程却不行
  • 子线程异常无法用传统方法(try-catch)捕获(类似main方法中执行thread.start,抛出异常是在子线程的run中,而try-catch的是主线程main,所以捕获不到)
  • 不能直接捕获会导致一些后果(无法捕获到异常,做相应的重试操作逻辑)

2、两种解决方案

方案一(不推荐):手动在每个run方法里进行try catch

public class CanCatchDirectly implements Runnable{
    public static void main(String[] args) throws InterruptedException {
        new Thread(new CanCatchDirectly(), "MyThread-1").start();
        Thread.sleep(300);
        new Thread(new CanCatchDirectly(), "MyThread-2").start();
        Thread.sleep(300);
        new Thread(new CanCatchDirectly(), "MyThread-3").start();
        Thread.sleep(300);
        new Thread(new CanCatchDirectly(), "MyThread-4").start();
    }
    
        @Override
    public void run() {
        try {
            throw new RuntimeException();
        } catch (RuntimeException e) {
            System.out.println("Caught Exception");
        }
        
    }
}
//输出结果
Caught Exception
Caught Exception
Caught Exception
Caught Exception

方案二(推荐):利用UncaughtExceptionHandler

(1)UncaughtExceptionHandler接口

(2)void uncaughtException(Thread t, Throwable e);

Thread.java
————————
@FunctionalInterface
    public interface UncaughtExceptionHandler {
        /**
         * Method invoked when the given thread terminates due to the
         * given uncaught exception.
         * <p>Any exception thrown by this method will be ignored by the
         * Java Virtual Machine.
         * @param t the thread
         * @param e the exception
         */
        void uncaughtException(Thread t, Throwable e);
    }
————————

(3)异常处理器的调用策略

(4)自己实现

  • 给程序统一设置
  • 给每个线程单独设置
  • 给线程池设置
1、自己的UncaughtExceptionHandler
/**
 * MyUncaughtExceptionHandler
 *
 * @author venlenter
 * @Description: 自己的UncaughtExceptionHandler
 * @since unknown, 2020-04-28
 */
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    private String name;

    public MyUncaughtExceptionHandler(String name) {
        this.name = name;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        Logger logger = Logger.getAnonymousLogger();
        logger.log(Level.WARNING, "线程异常,终止了" + t.getName(), e);
        System.out.println(name + "捕获了异常" + t.getName() + "异常" + e);
    }
}

2、使用自己的UncaughtExceptionHandler,触发
/**
 * UseOwnUncaughtExceptionHandler
 *
 * @author venlenter
 * @Description: 使用自己的UncaughtExceptionHandler
 * @since unknown, 2020-04-28
 */
public class UseOwnUncaughtExceptionHandler implements Runnable {
    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-1").start();
        Thread.sleep(300);
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-2").start();
        Thread.sleep(300);
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-3").start();
        Thread.sleep(300);
        new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-4").start();

    }
    @Override
    public void run() {
        throw new RuntimeException();
    }
}
//输出结果
捕获器1捕获了异常MyThread-1异常java.lang.RuntimeException
四月 28, 2020 11:34:06 下午 ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止了MyThread-1
java.lang.RuntimeException
	at ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.UseOwnUncaughtExceptionHandler.run(UseOwnUncaughtExceptionHandler.java:24)
	at java.lang.Thread.run(Thread.java:748)

四月 28, 2020 11:34:06 下午 ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
捕获器1捕获了异常MyThread-2异常java.lang.RuntimeException
警告: 线程异常,终止了MyThread-2
java.lang.RuntimeException
	at ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.UseOwnUncaughtExceptionHandler.run(UseOwnUncaughtExceptionHandler.java:24)
	at java.lang.Thread.run(Thread.java:748)

四月 28, 2020 11:34:07 下午 ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
...

3、线程的未捕获异常-常见面试问题

(1)为什么要全局处理?如何全局处理异常?不处理行不行?

  • 为什么要全局处理:统一处理,方便,不用每个地方都处理
  • 如何全局处理:定义一个自己的UncaughtExceptionHandler,然后Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));
  • 必须得处理

(2)run方法是否可以抛出异常?如果抛出异常,线程的状态会怎么样?

  • run没有声明throws exception,所以只能try-catch
  • 如果在run中try-catch没有捕获,漏了,则会抛出异常,线程会中止运行,打印出堆栈

(3)线程中如何处理某个未处理异常?

  • 使用全局处理ExceptionHandler

笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章