在Java程序的主线程中调用System.exit(0)和Thread.currentThread()。interrupt()有什么区别?

两者都会导致程序停止执行。 但很明显,这种情况必然存在一些差异。 这些是什么?

概要

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

线程中断

我担心你的第一句话是错的。 Thread.currentThread().interrupt()不会停止线程或程序。

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

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

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

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

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

exception和System.exit(int)

System.exit(int)的Javadoc说:

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

所以调用exit()将(几乎)肯定会停止你的程序。 与抛出RuntimeException (或Error )相反,这不能在调用堆栈的某处捕获,也不依赖于是否有其他线程在运行。 另一方面,未捕获的exception终止抛出它的线程,但如果有任何其他(非守护进程)线程,程序将继续运行。

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

Runtime.halt(INT)

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

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

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

应谨慎使用此方法。 与exit方法不同,此方法不会导致启动关闭挂钩,并且如果已启用finalization-on-exit,则不会运行未读取的终结器。

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

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

然而, System.exit(0)导致您的系统结束..并且所有线程都被杀死..