線程執行完run方法便可正常退出,若是發生了沒有捕獲的異常則會異常退出。大多數狀況下,因爲異常致使的線程退出都不是咱們想要的。因此在編寫的代碼的時候要儘量的捕獲處理能夠處理的異常,可是也不能光簡單的捕獲異常而後什麼也不作。下面介紹線程異常的處理辦法。
JVM爲咱們提供了線程的未捕獲異常處理機制,經過Thread的setUncaughtExceptionHandler方法:
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
能夠設置當前線程的未捕獲異常處理器。以下面的例子就經過設置uncaughtExceptionHandler成功捕獲到了除0異常:
public static void main(String[] args) throws InterruptedException { Thread t = new Thread(new UncaughtException.Run());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("uncaughtExceptionHandler catch a Exception---------");
System.out.println(e.getMessage());
}
});
t.start();
Thread.sleep(100);
}
static class Run implements Runnable{br/>@Override
public void run() {
System.out.println("runnable run---------------");
int i = 1/0;
}
}
結果:
runnable run---------------
uncaughtExceptionHandler catch a Exception---------
/ by zero
線程出現未捕獲異常後,JVM將調用Thread中的dispatchUncaughtException方法把異常傳遞給線程的未捕獲異常處理器。
/**html
intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
方法的描述已經清楚地說明了這個方法只是提供給JVM調用的,getUncaughtExceptionHandler方法並無簡單返回設置好的uncaughtExceptionHandler:
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
可見,若是沒有設置uncaughtExceptionHandler,將使用線程所在的線程組來處理這個未捕獲異常。線程組ThreadGroup實現了UncaughtExceptionHandler,因此能夠用來處理未捕獲異常。ThreadGroup類定義:
class ThreadGroup implements Thread.UncaughtExceptionHandler
ThreadGroup實現的uncaughtException以下:
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 \""app
t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
默認狀況下,線程組處理未捕獲異常的邏輯是,首先將異常消息通知給父線程組,而後嘗試利用一個默認的defaultUncaughtExceptionHandler來處理異常,若是沒有默認的異常處理器則將錯誤信息輸出到System.err。也就是JVM提供給咱們亨達返傭www.fx61.com/brokerlist/HantecGlobal.html設置每一個線程的具體的未捕獲異常處理器,也提供了設置默認異常處理器的方法。
設置了默認的異常處理器後,系統中全部未直接設置異常處理器的線程將使用這個默認的異常處理器。
public void defaultWay(){
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("I catch a exception from " + Thread.currentThread().getName() + ":" + Thread.currentThread().getThreadGroup().getName());
}
});
ThreadGroup myGroup = new ThreadGroup("myGroup");
new Thread(myGroup, new Runnable() {br/>@Override
public void run() {
int i = 1/0;
}
}, "thread1").start();
new Thread(myGroup, new Runnable() {br/>@Override
public void run() {
int i = 1/0;
}
}, "thread2").start();
}
這段代碼建立了兩個線程,而且它們都會拋出異常,最終由統一的默認異常處理器來處理。結果:
I catch a exception from thread1:myGroup
I catch a exception from thread2:myGroup
固然,出現上面的結果是由於使用了默認的ThreadGroup,咱們能夠破壞它這個機制。若是把上面代碼中的ThreadGroup換成下面的BadGroup則狀況會發生變化:
class BadGroup extends ThreadGroup{
public BadGroup(String name) {br/>super(name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("I am a bad group and do nothing");
}
}
若是使用了BadGroup得出結果將是打印兩條I am a bad group and do nothing。
上面的例子中,不管是ThreadGroup或者BadGroup都主動的給線程設置了線程組,那麼若是不給線程設置線程組會怎麼樣呢?還會正常的使用默認異常處理器嗎?這些跟線程組的來源相關,先看一個例子:
public void mainGroup() throws InterruptedException {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("I catch a exception from " + Thread.currentThread().getName() + ":" + Thread.currentThread().getThreadGroup().getName());
}
});
new Thread(new Runnable() {br/>@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " said my thread group is " + Thread.currentThread().getThreadGroup().getName());
new Thread(new Runnable() {br/>@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " said my thread group is " + Thread.currentThread().getThreadGroup().getName());
int i = 1/0;
}
}, "thread2").start();
}
}, "thread1").start();ide
Thread.sleep(10);
}
這個方法中,首先建立啓動了一個線程,而後又在這個線程中建立啓動了另外一個線程,它們都沒有主動設置線程組。然而,它們都是有線程組的,其執行的結果以下:
thread1 said my thread group is main
thread2 said my thread group is main
I catch a exception from thread2:main
虛擬機執行main方法的線程屬於一個名字叫作「main」的線程組。在應用程序中,建立一個線程的時候若是沒有從新制定線程組,則會繼承這個「main」線程組。也就是說全部的線程都會有線程組,即便咱們在構造線程時顯示的傳入null值的線程組,最終JVM也會爲咱們分配到一個線程組。Thread的init方法決定了這個特性:
if (g == null) {
/ Determine if it's an applet or not /
/ If there is a security manager, ask the security manager
what to do. /
if (security != null) {
g = security.getThreadGroup();
}
/ If the security doesn't have a strong opinion of the matter
use the parent thread group. /
if (g == null) {
g = parent.getThreadGroup();
}
}
首先咱們要先定義這個線程異常捕獲的處理器
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕獲異常處理方法:" + e);
}
}
咱們有三種方式使用該線程異常捕獲器:
一、在建立線程的時候進行設置
Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();
二、使用Executors建立線程時,還能夠在TreadFactory中設置
ExecutorService exec = Executors.newCachedThreadPool(new ThreadFactory(){br/>@Override
public Thread newThread(Runnable r) {
Thread thread = newThread(r);
thread.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
return thread;
}
});
exec.execute(new ExceptionThread());
三、若是咱們只須要一個線程異常處理器處理線程的異常,那麼咱們能夠設置一個默認的線程異常捕獲器,當線程出現異常時,
若是咱們沒有指定線程的異常捕獲器,並且線程組也沒有設置(線程組不用考慮,由於這是一個不成功的嘗試),那麼就會使用
默認的線程異常捕獲器。
// 設置默認的線程異常捕獲處理器
Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
經過以上方法就能夠捕獲並處理線程的異常了。this