在Java中,執行緒中的例外是不能拋出到呼叫該執行緒的外部方法中捕獲的,
因為執行緒是獨立執行的代碼片斷,執行緒的問題應該由執行緒自己來解決,而不要委托到外部,”基于這樣的設計理念,在Java中,執行緒方法的例外都應該在執行緒代碼邊界之內(run方法內)進行try catch并處理掉,換句話說,我們不能捕獲從執行緒中逃逸的例外,
public static void main(String[] args){
try {
new Thread( () -> {
int i = 1/ 0;
}).start();
}catch (Exception e){
System.out.println(1);
}
}

可以看到,外部的catch并沒有捕捉到,
Thread類的run()方法宣告,方法宣告上沒有對拋出例外進行任何約束,也就是例外不會拋到外部,如果內部沒有catch,那么Thread的默認例外處理就是呼叫 System.err 進行輸出,也就是直接列印到控制臺了,
解決方案
執行緒內部顯式try…catch
public static void main(String[] args){
new Thread( () -> {
try {
int i = 1/ 0;
}catch (Exception e){
System.out.println("1");
}
}).start();
}

可以看到我們在執行緒內部顯式的進行try/catch,例外被捕獲,
給執行緒定義例外處理器
查看Thread類的原始碼,我們可以看到有個dispatchUncaughtException方法,此方法就是用來處理執行緒中拋出的例外的,JVM會呼叫dispatchUncaughtException方法來尋找例外處理器(UncaughtExceptionHandler),處理例外,
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
/**
* 獲取用來處理未捕獲例外的handler,如果沒有設定則回傳當前執行緒所屬的ThreadGroup
*
**/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
uncaughtExceptionHandler 默認為null,null的話就呼叫執行緒所屬group的默認handler
// 這里也就是列印到控制臺
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
所以我們可以通過設定Thread的uncaughtExceptionHandler 來設定例外處理器
public static void main(String[] args){
Thread thread = new Thread(() -> {
int i = 1 / 0;
});
thread.setUncaughtExceptionHandler((t, e) -> System.out.println("捕捉到例外"));
thread.start();
}

執行緒池自定義處理例外
在執行緒池,我們可以批量的為所有執行緒設定uncaughtExceptionHandler,執行緒是由ThreadFactory產生的,所以我們可以通過這里入手,
通過復寫ThreadFactory的newThread就可實作,
public class ThreadExceptionDemo {
private static final int CORE_POOL_SIZE = 3;
private static final int MAX_POOL_SIZE = 100;
private static final int QUEUE_CAPACITY = 5;
private static final Long KEEP_ALIVE_TIME = 5L;
public static void main(String[] args){
// 在建構式塞進去我們要的ThreadFactory
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new MyThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
executor.execute(()->{
int i = 1 / 0;
});
}
}
class MyThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕捉到了");
}
});
return thread;
}
}

通過Future的get方法捕獲例外
執行緒池的submit是帶有回傳值的
public static void main(String[] args){
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future future = executorService.submit(()->{
int i = 1 / 0;
});
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println("捕捉到了");
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/257444.html
標籤:java
下一篇:Java新手基礎(隨筆)
