在 Java 程序的主线程中调用 System.exit(0) 和 Thread.currentThread().interrupt() 有什么区别?
两者都会导致程序停止执行。很明显,这种情况的发生方式肯定存在一些差异。它们是什么?
两者都会导致程序停止执行。很明显,这种情况的发生方式肯定存在一些差异。它们是什么?
thread.interrupt()
不会停止线程。它用于多线程程序中的协调。除非您确切地知道自己在做什么,否则不要使用它。RuntimeException
System.exit(int)
几乎总是终止程序并返回状态代码。System.exit(int)
Runtime.getRuntime().halt(int)
恐怕你的第一句话是错的。 不会停止线程或程序。Thread.currentThread().interrupt()
中断线程是发出它应该停止的信号的一种方式,但这是一种合作努力:线程中的代码应该不时检查中断状态,并且(在大多数情况下 - 但即使这只是可选的)如果被中断,也应该停止。如果它不这样做,什么都不会发生。
具体来说,中断线程(任何线程,包括当前正在执行的线程)只会设置中断标志。标准库中的某些方法会抛出一个 InterruptedException,但这也只是一种发出线程已中断信号的方法。在这种情况下应该做什么取决于该线程中运行的代码。
以下是Brian Goetz的Java Concurrency in Practice一书中的相关部分:
线程提供用于中断线程和查询线程是否已中断的中断方法。每个线程都有一个布尔属性,表示其中断状态;中断线程会设置此状态。
中断是一种合作机制。一个线程不能强迫另一个线程停止它正在做的事情并做其他事情;当线程 A 中断线程 B 时,A 只是请求 B 在到达方便的停止点时停止它正在做的事情,如果它感觉像这样的话。虽然 API 或语言规范中没有任何内容要求任何特定的应用程序级语义进行中断,但中断的最明智用法是取消活动。响应中断的阻止方法可以更轻松地及时取消长时间运行的活动。
终止当前正在运行的 Java 虚拟机。该参数用作状态代码;按照惯例,非零状态代码表示异常终止。
因此,呼叫(几乎)肯定会停止您的程序。与抛出一个(或一个)相反,这不能被捕获到调用堆栈的某个地方,它也不依赖于是否有其他线程在运行。另一方面,未捕获的异常会终止引发异常的线程,但如果存在任何其他(非守护程序)线程,程序将继续运行。exit()
RuntimeException
Error
抛出异常的另一个区别是不会将任何内容打印到控制台(与未捕获的异常一样),而是使程序返回特定的状态代码。状态代码有时用于 shell 或批处理脚本中,但除此之外,它们不是很有用。exit()
最后(为了完整性的缘故),我想指出退出Java程序的第三种可能性。当调用 时(或程序以某种其他方式结束),运行时会在 Java 虚拟机停止之前执行一些清理工作。这在 Runtime.exit(int) 的 Javadoc 中进行了描述(由 调用:System.exit(int)
System.exit(int)
虚拟机的关机顺序由两个阶段组成。在第一阶段,所有已注册的关闭挂钩(如果有)都以某种未指定的顺序启动,并允许并发运行,直到它们完成。在第二阶段,如果启用了退出时终结,则运行所有未调用的终结器。完成此操作后,虚拟机将停止。
如果任何关机挂接或终结器被阻止完成,例如由于死锁,程序可能永远不会真正退出。保证 JVM 暂停的唯一方法是 Runtime.halt(int):
使用此方法时应格外小心。与 exit 方法不同,此方法不会导致启动关闭挂接,并且如果启用了退出时终结,则不会运行未调用的终结器。
如果正在运行其他(非守护进程)线程,那么如果停止主线程,JVM 将不会退出。System.exit() 杀死所有其他线程。