使用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