🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 如何使用`UncaughtExceptionHandler`重新启动线程 > 原文: [https://howtodoinjava.com/java/multi-threading/how-to-restart-thread-using-uncaughtexceptionhandler/](https://howtodoinjava.com/java/multi-threading/how-to-restart-thread-using-uncaughtexceptionhandler/) 我们已经知道 Java 中有两种异常。 受检的异常和非受检的异常。 必须在方法的`throws`子句中指定受检的异常或将其捕获在其中。 无需指定或捕获非受检的异常。 当在`Thread`对象的`run()`方法内引发受检异常时,由于`run()`方法不接受`throws`子句,因此我们必须相应地对其进行处理。 但是,当在`Thread`对象的`run()`方法内引发非受检的异常时,默认行为是在控制台中写入栈跟踪(或将其记录在错误日志文件中)并退出程序。 幸运的是,Java 为我们提供了一种机制来捕获和处理`Thread`对象中抛出的非受检的异常,从而避免程序结束。 这可以使用`UncaughtExceptionHandler`完成。 让我们以`UncaughtExceptionHandler`用法为例。 在此示例中,我们创建了一个线程,该线程尝试解析一些应该为整数的字符串。 我们编写了`run()`方法,使其在执行过程中抛出“ `java.lang.NumberFormatException`”。 由于程序不会尝试捕获此异常,因此异常会在 JVM 级别浮动,并且线程被杀死。 这绝对是正常行为,但可能不是您期望的行为。 ## 不使用`UncaughtExceptionHandler` 在现实生活中的应用程序中,即使几次失败,您也想尝试执行一次多次重要任务。 下面的示例演示了用例,首先不使用`UncaughtExceptionHandler`; 导致线程在失败后立即死亡。 **`Task.java`** ```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`** ```java public class DemoThreadExample { public static void main(String[] args) { Task task = new Task(); Thread thread = new Thread(task); thread.start(); } } ``` 下面是运行线程时得到的输出: ```java 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`** ```java class ExceptionHandler implements UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.printf("An exception has been captured\n"); System.out.printf("Thread: %s\n", t.getId()); System.out.printf("Exception: %s: %s\n", e.getClass().getName(), e.getMessage()); System.out.printf("Stack Trace: \n"); e.printStackTrace(System.out); System.out.printf("Thread status: %s\n", t.getState()); new Thread(new Task()).start(); } } ``` 现在,将此异常处理程序添加到线程中。 ```java 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")); } } ``` 现在再次运行上面的示例。 这将连续运行。 在现实生活中,如果该任务能够完成任务,那么它将在不引发任何异常的情况下退出并完成其生命周期。 ```java 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`也可以用于使日志记录更加健壮,而无需重新启动线程,因为在线程执行失败时,默认日志通常无法提供足够的上下文信息。** **祝您学习愉快!**