24

两者都会导致程序停止执行。不过,很明显,这种情况的发生方式肯定存在一些差异。这些是什么?

4

3 回答 3

43

概括

  1. thread.interrupt()不停止线程。它用于多线程程序中的协调。除非您确切知道自己在做什么,否则不要使用它。
  2. 抛出RuntimeException将(通常)终止线程但不一定终止程序。
  3. System.exit(int) 几乎总是终止程序并返回状态码。
  4. 在不寻常的情况下,System.exit(int)可能不会真正停止程序。Runtime.getRuntime().halt(int)另一方面,总是如此。

线程中断

恐怕你的第一句话是错误的。Thread.currentThread().interrupt()不会停止线程或程序。

中断线程是表示它应该停止的一种方式,但这是一种合作努力:线程中的代码应该不时检查中断状态并且(在大多数情况下 - 但即使这只是可选的)应该如果被中断则停止。如果它不这样做,什么都不会发生。

具体来说,中断一个线程(任何线程,包括当前正在执行的线程)只会设置中断标志。标准库中的某些方法会抛出 InterruptedException,但这也只是表示线程已被中断的一种方式。在这种情况下应该做什么取决于该线程中运行的代码。

以下是Brian Goetz的Java Concurrency in Practice一书中的相关部分:

Thread提供了中断线程的方法,用于查询线程是否被中断。每个线程都有一个布尔属性,表示其中断状态;中断线程设置此状态。

中断是一种合作机制。一个线程不能强迫另一个线程停止它正在做的事情并做其他事情;当线程 A 中断线程 B 时,A 只是请求 B 在它到达一个方便的停止点时停止它正在做的事情,如果它感觉喜欢的话。虽然 API 或语言规范中没有任何内容需要任何特定的应用程序级语义中断,中断最明智的用途是取消活动。响应中断的阻塞方法可以更容易地及时取消长时间运行的活动。

异常和 System.exit(int)

JavadocSystem.exit(int)说:

终止当前运行的 Java 虚拟机。该参数用作状态码;按照惯例,非零状态码表示异常终止。

所以调用exit()(几乎)肯定会停止你的程序。与抛出 a RuntimeException(或 an Error)相比,这不能在调用堆栈的某个地方被捕获,它也不取决于是否有其他线程在运行。另一方面,未捕获的异常会终止引发它的线程,但如果有任何其他(非守护程序)线程,程序将继续运行。

抛出异常的另一个区别是它exit()不会向控制台打印任何内容(就像未捕获的异常一样),而是使程序返回特定的状态代码。状态码有时用于 shell 或批处理脚本,但除此之外,它们不是很有用。

运行时.halt(int)

最后(为了完整起见),我想指出退出 Java 程序的第三种可能性。当System.exit(int)被调用(或程序以某种其他方式结束)时,运行时会在 Java 虚拟机停止之前进行一些清理工作。这在Runtime.exit(int)的 Javadoc 中进行了描述(由以下方式调用System.exit(int)

虚拟机的关闭顺序包括两个阶段。在第一阶段,所有已注册的关闭挂钩(如果有)都以某种未指定的顺序启动,并允许同时运行直到它们完成。在第二阶段,如果 finalization-on-exit 已启用,则所有未调用的终结器都会运行。完成此操作后,虚拟机将停止。

如果任何关闭挂钩或终结器无法完成,例如由于死锁,程序可能永远不会真正退出。保证 JVM 停止的唯一方法是Runtime.halt(int)

使用此方法时应格外小心。与 exit 方法不同,如果 finalization-on-exit 已启用,此方法不会导致关闭挂钩启动并且不会运行未调用的终结器。

于 2012-09-24T20:35:36.683 回答
20

如果有其他(非守护程序)线程在运行,则如果您停止主线程,JVM 将不会退出。System.exit() 杀死所有其他线程。

于 2012-09-24T20:32:54.410 回答
1

在多线程应用程序中,有多个线程在执行。Thread.currentThread().interrupt()只会中断你当前正在执行的线程,但剩余的线程会运行,即使你的主线程被中断了..

然而,System.exit(0)结果你的系统被结束了..所有线程都被杀死了..

于 2012-09-24T20:35:10.293 回答