線程的異常處理
setDefaultUncaughtExceptionHandler()
:設(shè)置當(dāng)線程由于未捕獲到異常而突然終止足删,并且沒有為該線程定義其他處理程序時所調(diào)用的默認(rèn)處理程序。Thread.setDefaultUncaughtExceptionHandler(new ThreadUncaughtExceptionHandler())
線程異常處理實(shí)例
package com.thread.study;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
public class ThreadException {
/** 日志 */
private static final Logger LOGGER = getLogger(ThreadException.class);
public static void main(String[] args) {
//異常不處理
new Thread(() -> {
int i = 1/0;
}, "張三").start();
//在線程內(nèi)異常處理
new Thread(() -> {
try {
int i = 1/0;
} catch (Exception e) {
LOGGER.error("線程發(fā)生了異常野舶,線程內(nèi)處理", e);
}
}, "李四").start();
// 在線程外處理異常
try {
new Thread(() -> {
int i = 1/0;
}, "王五").start();
} catch (Exception e) {
LOGGER.error("線程發(fā)生了異常蒜焊,線程外處理", e);
}
// 自定義線程異常處理異常
Thread thread = new Thread(() -> {
int i = 1/0;
},"趙六");
thread.setUncaughtExceptionHandler(new ThreadUncaughtExceptionHandler());
thread.start();
}
}
// 自定義線程異常
class ThreadUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
/** 日志 */
private static final Logger LOGGER = getLogger(ThreadUncaughtExceptionHandler.class);
/**
* Thread t 發(fā)生異常的線程
* Throwable e 發(fā)生的異常
*/
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("線程發(fā)生了異常喳坠,自定義處理构回。{}", t, e);
}
}
打印結(jié)果
Exception in thread "張三" java.lang.ArithmeticException: / by zero
at com.thread.study.ThreadException.lambda$main$0(ThreadException.java:14)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "王五" java.lang.ArithmeticException: / by zero
at com.thread.study.ThreadException.lambda$main$2(ThreadException.java:29)
at java.lang.Thread.run(Thread.java:745)
主線程執(zhí)行完了
10:32:02.518 [李四] ERROR com.thread.study.ThreadException - 線程發(fā)生了異常谷炸,線程內(nèi)處理
java.lang.ArithmeticException: / by zero
at com.thread.study.ThreadException.lambda$main$1(ThreadException.java:20)
at java.lang.Thread.run(Thread.java:745)
10:32:02.518 [趙六] ERROR com.thread.study.ThreadUncaughtExceptionHandler - 線程發(fā)生了異常,自定義處理畦徘。Thread[趙六,5,main]
java.lang.ArithmeticException: / by zero
at com.thread.study.ThreadException.lambda$main$3(ThreadException.java:37)
at java.lang.Thread.run(Thread.java:745)
線程異常處理總結(jié):
- 線程中如果發(fā)生異常毕籽,不處理與在線程外處理效果是一樣的。
- 線程中如果發(fā)生異常井辆,在線程中處理可以捕捉到異常关筒,線程的異常不影響其他線程的執(zhí)行。
- 線程中如果發(fā)生異常杯缺,使用線程內(nèi)的try...catch和自定義異常都是可以處理的蒸播,并可以獲取線程內(nèi)的異常信息。
- 線程內(nèi)的try...catch和自定義異常處理異常的區(qū)別在于萍肆,線程內(nèi)的try...catch只能針對一個線程袍榆,自定義異常可以針對一組線程塘揣。
線程通過Future的get方法捕獲異常
package com.thread.study;
import org.slf4j.Logger;
import java.util.concurrent.*;
import static org.slf4j.LoggerFactory.getLogger;
public class ThException {
/** 日志 */
private static final Logger LOGGER = getLogger(ThreadException.class);
public static void main(String[] args) {
// 線程通過Future的get方法捕獲異常
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Object> future = executorService.submit(new Callable() {
@Override
public String call() throws Exception {
int i = 1 / 0;
return "線程通過Future創(chuàng)建線程";
}
});
try {
String reStr = (String) future.get();
System.out.println(reStr);
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("線程發(fā)生了異常包雀,線程通過Future的get方法捕獲異常", e);
}
executorService.shutdown();
System.out.println("主線程執(zhí)行完了");
}
}
// 打印結(jié)果
/*
11:10:41.841 [main] ERROR com.thread.study.ThreadException - 線程發(fā)生了異常,線程通過Future的get方法捕獲異常
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.thread.study.ThException.main(ThException.java:26)
Caused by: java.lang.ArithmeticException: / by zero
at com.thread.study.ThException$1.call(ThException.java:21)
at com.thread.study.ThException$1.call(ThException.java:18)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
主線程執(zhí)行完了
*/
通過Future的get方法處理總結(jié):
在submit之后可以獲得一個線程執(zhí)行結(jié)果的Future對象勿负,而如果子線程中發(fā)生了異常馏艾,通過future.get()獲取返回值時劳曹,可以捕獲到ExecutionException異常奴愉,從而知道子線程中發(fā)生的異常信息。