第九章、核心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併發核心知識體系精講》

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