未处理的运行时异常是否会使整个服务器崩溃?

Does an unhandled runtime exception crash the whole server?

未处理的运行时异常会停止整个服务器(即 Spring 引导应用程序)还是仅停止特定的 HTTP 请求?

未处理的运行时异常确实会立即关闭正常的 Java 应用程序,对吗?

只是有问题的线程

未处理的 RuntimeException 将终止线程,而不是应用程序。通常每个 HTTP 请求都由其自己的线程处理,因此服务器中的任何其他内容都不会受到影响。不知道服务器是怎么处理死线程的。明智之举可能是为即将到来的请求创建一个新线程。

只有当所有 线程(所谓的恶魔线程除外)都终止时,您的Spring 启动应用程序才会停止。这反过来意味着在一个没有线程的应用程序中——一个在主线程中拥有所有运行ning的应用程序——一个未捕获的异常(RuntimeException或其他类型) 把整个程序打下来。

在大多数应用程序中,哪个 线程被杀死很重要。您的应用程序可能有更多线程处理 HTTP 请求,并且可以根据需要生成新线程。在这种情况下,除非用户发送了这个 HTTP 请求,否则线程死亡几乎不会被注意到。其他线程可能对服务器的功能更重要,这样的线程被杀死,虽然不会完全停止服务器,但会阻止它正常工作。再举一个不同的例子,如果桌面应用程序中的事件调度线程被异常杀死,应用程序将无法再接受用户输入。

亲自尝试一下

尝试一下并不需要太多时间。以下程序生成一个线程,该线程抛出未处理的异常。

public class DemoUnhandledException {

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> { throw new RuntimeException("Demo"); }).start();
        TimeUnit.MINUTES.sleep(1);
        System.out.println("A minute later the main thread is still alive and well");
    }

}

让程序运行整整一分钟得到完整的输出,即:

Exception in thread "Thread-0" java.lang.RuntimeException: Demo
  at ovv.so.exception.DemoUnhandledException.lambda[=11=](DemoUnhandledException.java:8)
  at java.base/java.lang.Thread.run(Thread.java:834)
A minute later the main thread is still alive and well

Link

How uncaught exceptions are handled in Java 在 Javamex

Will an unhandled runtime exception stop the whole server (i.e. Spring Boot application) or just the specific HTTP request ?

只是当前的 HTTP 请求...假设异常是由请求线程抛出的。 (如果是子线程抛出,它甚至不会终止HTTP请求。)


It is true that an unhandled runtime exception will instantly shut down normal Java application, right?

其实不对。

未捕获的异常导致抛出它的线程终止。在一个简单的 Java 应用程序中,只有一个(非守护进程)“主”线程,并且该线程上发生未捕获的异常,然后 JVM 退出 因为最后一个非守护进程线程已经终止.

但是如果有其他线程...未捕获的异常不会停止 JVM。

为了说明,运行 这个程序:

public class Test {
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                System.err.println("Caught " + e);
            }
        }).start();
        throw new RuntimeException("Goodbye cruel world");
    }
}

当您 运行 执行此操作时,您会观察到在堆栈跟踪打印(来自 main 中未捕获的异常)和程序实际结束之间有 10 秒的延迟。 JVM 正在等待子线程终止。


这也可以间接回答您的主要问题...除了:

  • 我们不确定请求线程是否是守护线程。
  • 我们不确定请求线程是否真的在捕获/处理您的请求处理代码抛出的异常。

可以这么说,框架通常会 做一些明智的事情 取决于抛出的异常是什么。例如,框架可能会通过尝试关闭来处理工作线程上的 Error 异常......基于错误可能已将 JVM 置于潜在的不安全/不可恢复状态。

Will an unhandled runtime exception stop the whole server (i.e. Spring Boot application) or just the specific HTTP request ?

网络服务器通常有一个thread pool来处理所有请求(例如tomcat)。在你的 controller 中发生的未捕获的异常最终会在某个地方被捕获,所以它不会导致 thread pool 中的 worker thread 被杀死。

Tomcat#AbstractEndpoint#processSocket:

Executor executor = getExecutor();
if (dispatch && executor != null) {
    // handle request in thread poll
    executor.execute(sc);
} 

我做了简单的调试。假设在你的 controller 中发生了未处理 exception,那么这个异常实际上被 FrameworkServlet#processRequest 捕获了。捕获后会被包裹成一个NestedServletException,继续向上层抛出。最终,它会被捕获并打印在 StandardWrapperValve#invoke.