一个线程中的StackOverFlow异常会导致应用程序停止吗?
我的应用程序中有六个线程正在运行。如果一个线程抛出 StackOverFlow 异常,所有线程或应用程序都会停止工作吗?
回答
通常 - 不,
一个线程中的异常不会杀死另一个线程;
除非....
稍微长一点的故事
Java 中有两种类型的线程:普通线程和守护线程,它们的区别仅在于退出时发生的情况。
当一个线程退出时,JVM 会清点正在运行的线程,并且
如果只有守护线程保持活动状态
JVM 启动有序关闭(意思是,它在main线程完成执行后关闭)。
当 JVM 停止时,任何剩余的守护线程都会被放弃——finally 块不会被执行,堆栈不会被解开——JVM 只是退出。
因此,当您的线程中有未处理的异常时,可能会出现以下两种情况之一:
- JVM 将关闭- 您的线程是最后一个正常线程,并且在 JVM 在该线程退出后执行另一次库存检查后,它将关闭,因为没有其他正常线程剩余(从概念上讲,JVM 认为,没有什么重要的东西在运行,因为守护线程永远不应该用于重要/不安全的操作);
- JVM 将继续运行- 您的线程不是最后一个正常线程,在其中发生未处理的异常后,JVM 将继续运行。
例如,在这种情况下:
public class EntryPoint {
public static void main(String[] args) throws Exception {
Thread t = new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
System.out.println("Thread " + Thread.currentThread().getName() + " " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.setDaemon(true);
t.start();
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
if (i == 4) {
throw new StackOverflowError("JVM exits in this case.");
}
System.out.println("Call number " + i);
}
}
}
一旦抛出异常,您的应用程序就会崩溃,因为没有正常的线程在运行;
而在这种情况下:
public class EntryPoint {
public static void main(String[] args) throws Exception {
Thread t = new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
System.out.println("Thread " + Thread.currentThread().getName() + " " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.setDaemon(false);
t.start();
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
if (i == 4) {
throw new StackOverflowError("JVM won't exit in this case.");
}
System.out.println("Call number " + i);
}
}
}
由 引用的普通线程t将继续执行。
最后的笔记
-
注意,JVM启动时(Java程序启动),它创建的所有线程(如垃圾收集器等内务线程)都是守护线程,除了主线程是普通线程;但是,如果您创建一个新线程,它会从创建它的线程继承类型;
-
我
.setDaemon(true)在第一个代码片段中明确设置,的唯一原因是线程类型是从创建它的线程继承的。