Java中的同步和异步异常

4

在阅读Java虚拟机规范时,我发现了异常(2.10 异常)

大多数异常是同步发生的,因为它们是由线程在执行动作时出现的。相比之下,异步异常可以在程序的任何执行点潜在地发生...

这两种类型有什么区别?

继续阅读,规范给出了一个异步异常的示例

异步异常的原因是:- 类Thread或ThreadGroup的stop方法被调用,或者- Java虚拟机实现中发生了内部错误。

但是,是什么使得线程类的stop方法在这方面特殊呢?

能否解释一下这两种类型的区别,并给出除所给示例以外的其他例子?


问题中提到的区别是:“大多数异常都是由发生异常的线程执行的操作同步引起的。”这让我想到异步异常是另一个线程的操作结果 ;) - AxelH
2个回答

1
停止方法可以从另一个线程调用,这可能会导致被停止的线程留下不一致状态的数据。
因此,Thread.stop()正在被移除。建议不要使用它。
区别在于异步异常是由另一个线程在代码的任何点触发的。
它们不应该在正常操作下发生。
JVM的特定实现可能有其他错误,但没有详尽的列表。
除了优雅地关闭之外,你几乎无法做任何事情。

这是唯一的异步异常示例吗?(我对此不太熟悉)这似乎更是本文的主题。 - AxelH
这不是你真正能够处理的情况,而且在正常操作下也不应该发生。 - Peter Lawrey
这在正常操作下不应该发生,这不就是异常的定义吗 ;) 所以你是在暗示那些异常(不仅仅是来自Thread.stop的异常)应该被简单地忽略?(看到你的编辑,这回答了我的最后一条评论) - AxelH
@AxelH,你应该优雅地关闭。虽然异常是异常情况,但在正常程序中它们经常发生,例如当套接字断开连接时。 - Peter Lawrey

1
这里有一个例子展示了两种类型的异常。考虑下面的代码片段,它们展示了两种不同的异常被抛出和处理:
public static void main(String[] args) throws Exception {
    try {
        syncException();
    } catch (RuntimeException re) {
        System.out.println("-1-");
        re.printStackTrace();
    }

    CompletableFuture<Void> f = null;
    try {
        f = asyncException();
    } catch (RuntimeException ex) {
        System.out.println("-2-" + Thread.currentThread().getName());
        ex.printStackTrace();
    }

    try {
        f.get();
    } catch (Exception ex) {
        System.out.println("-3-");
        ex.printStackTrace();
    }
}

同步异常

private static void syncException() {
    throw new RuntimeException("Sync exception @" + Thread.currentThread().getName());
}

而异步异常——在不同的线程中引发,与调用代码不同:

private static CompletableFuture<Void> asyncException() {
    return CompletableFuture.runAsync(() -> {
        throw new RuntimeException("Async exception @" + Thread.currentThread().getName());
    }, Executors.newFixedThreadPool(1));
}

现在,当执行该代码时,会产生以下堆栈跟踪:
同步异常的堆栈跟踪:
-1-
java.lang.RuntimeException: Sync exception @main
    at stackoverflow.Main.syncException(Main.java:34)
    at stackoverflow.Main.main(Main.java:11)

请注意,-2-没有被打印出来,因为该异常是异步的。请查看第三个catch块的堆栈跟踪,了解如何处理异步异常。请注意,引发异常的线程与打印堆栈跟踪的线程不同:
-3-
java.util.concurrent.ExecutionException: java.lang.RuntimeException: Async exception @pool-1-thread-1
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
    at stackoverflow.Main.main(Main.java:26)
Caused by: java.lang.RuntimeException: Async exception @pool-1-thread-1
    at stackoverflow.Main.lambda$0(Main.java:39)
    at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1626)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

相比之下,异步异常可以在程序的任何执行点潜在地发生...
对此的评论是:您会注意到,在线程pool-1-thread-1中的代码可能会在main线程执行的任何时间引发异常。这可能在不同线程之间是相对的。但在这个例子中,main线程是主要的程序执行,我们可以说"Async exception @ pool-1-thread-1"异常是异步发生的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接