# 如何使用`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`也可以用于使日志记录更加健壮，而无需重新启动线程，因为在线程执行失败时，默认日志通常无法提供足够的上下文信息。**

**祝您学习愉快！**