使用UncaughtExceptionHandler重啟線程
使用UncaughtExceptionHandler重啟線程
我們已經知道,Java中有兩種異常,即已檢測異常和未檢測異常。已檢測的異常必須在拋出語句(throws clause)的方法中指定或者捕獲。未檢測的異常不需要指定或捕獲。因為run()方法不接受拋出語句,所以當一個檢測的異常在一個Thread對象的 run()方法中拋出,我們需要對其進行捕獲并做相應的處理。但是當一個未檢測的異常在一個線程的run()方法中拋出,默認的行為是將堆棧跟蹤信息寫到 控制臺中(或者記錄到錯誤日志文件中)然后退出程序。
幸運的是,Java為我們提供了一個機制,用來捕獲并處理在一個線程對象中拋出的未檢測異常,以避免程序終止。我們可以通過UncaughtExceptionHandler來實現這種機制。
讓我們來做個UncaughtExceptionHandler的使用 示例。在這個例子中,我們已經創建一個線程,這個線程嘗試解析一些本來應該是整數的字符串。我們已經寫出run()方法,讓它在執行時拋出 java.lang.NumberFormatException。當程序不去捕獲異常時,異常經過JVM的同時線程也被殺死。這確實屬于正常的行為,但 不是我們希望看到的。
不使用UncaughtExceptionHandler
在現實生活的應用中,對于一個關鍵的任務,雖然已經失敗了幾次,但是你依然愿意嘗試再執行幾次。下面的例子解釋了這個用例,首先不使用UncaughtExceptionHandler時,線程在執行失敗之后立即終止。
Task.java
class Task implements Runnable
{
@Override
public void run()
{
System.out.println(Integer.parseInt("123"));
System.out.println(Integer.parseInt("234"));
System.out.println(Integer.parseInt("345"));
System.out.println(Integer.parseInt("XYZ")); //This will cause NumberFormatException
System.out.println(Integer.parseInt("456"));
}
} DemoThreadExample.java
public class DemoThreadExample
{
public static void main(String[] args)
{
Task task = new Task();
Thread thread = new Thread(task);
thread.start();
}
} 下面是線程運行時的輸出:
123
234
345
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "XYZ"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
at java.lang.Thread.run(Unknown Source) 使用UncaughtExceptionHandler之后
首先,我們實現UncaughtExceptionHandler接口,用來捕獲運行時的任意未檢測的異常。
ExceptionHandler.java
class ExceptionHandler implements UncaughtExceptionHandler
{
public void uncaughtException(Thread t, Throwable e)
{
System.out.printf("An exception has been capturedn");
System.out.printf("Thread: %sn", t.getId());
System.out.printf("Exception: %s: %sn", e.getClass().getName(), e.getMessage());
System.out.printf("Stack Trace: n");
e.printStackTrace(System.out);
System.out.printf("Thread status: %sn", t.getState());
new Thread(new Task()).start();
}
} 將異常處理程序添加到線程:
class Task implements Runnable
{
@Override
public void run()
{
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
System.out.println(Integer.parseInt("123"));
System.out.println(Integer.parseInt("234"));
System.out.println(Integer.parseInt("345"));
System.out.println(Integer.parseInt("XYZ")); //This will cause NumberFormatException
System.out.println(Integer.parseInt("456"));
}
} 再次運行上面的例子,會發現線程能夠持續執行。實際上,如果線程完成了任務,那么它在退出時不會拋出任何異常,從而完成自身生命周期。
123
234
345
An exception has been captured
Thread: 1394
Exception: java.lang.NumberFormatException: For input string: "XYZ"
Stack Trace:
java.lang.NumberFormatException: For input string: "XYZ"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
at java.lang.Thread.run(Unknown Source)
Thread status: RUNNABLE
123
234
345
An exception has been captured
Thread: 1395
Exception: java.lang.NumberFormatException: For input string: "XYZ"
Stack Trace:
java.lang.NumberFormatException: For input string: "XYZ"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
at java.lang.Thread.run(Unknown Source)
Thread status: RUNNABLE
123
234
345 上面的程序實現幫你運行一個線程,在完成任務之前,這個線程會持續運行。通過其他多線程的思想同樣可以實現這種情況。
請注意:UncaughtExceptionHandler可以在無需重啟線程的條件下,將日志記錄變得更加健壯,因為默認日志在線程執行失敗時,不會提供足夠的上下文信息。
學習愉快!
原文鏈接: howtodoinjava 翻譯: ImportNew.com - Angus
譯文鏈接: http://www.importnew.com/14434.html