- 線程的未捕獲異常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併發核心知識體系精講》