JVM 有以下两种关闭方式:
-
受控过程:当调用了
System.exit()
方法、按下 CTRL+C
或最后一个非守护线程终止时,JVM 将开始关闭其进程。
-
突然的方式:当接收到一个 kill 信号、调用
Runtime.getRuntime().halt()
方法或任何类型的 OS panic 时,JVM 将开始关闭其进程。
JVM 关闭钩子
关闭钩子实际上是一个已经初始化但尚未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭钩子并让它们并发运行。当所有钩子完成后,如果启用了退出时的终结,则会运行所有未被调用的终结器。最后,虚拟机会停止。需要注意的是,在关闭过程中守护线程将继续运行,如果关闭是由调用 exit 方法引发的话,非守护线程也会继续运行。
JVM 关闭钩子:addShutdownHook(Thread hook)
方法
Runtime addShutdownHook(Thread hook)
方法注册一个新的虚拟机关闭钩子。
声明
以下是 java.lang.Runtime.addShutdownHook()
方法的声明:
public void addShutdownHook(Thread hook)
参数
-
hook
- 一个已经初始化但尚未启动的 Thread
对象。
返回值
此方法不返回任何值。
异常
-
IllegalArgumentException
- 如果指定的钩子已经被注册,或者可以确定钩子已经在运行或已经运行过。
-
IllegalStateException
- 如果虚拟机已经开始关闭过程。
-
SecurityException
- 如果存在安全管理员并且它拒绝 RuntimePermission("shutdownHooks")
。
JVM 关闭钩子示例
在这个例子中,我们通过扩展 Thread
类来创建一个名为 CustomThread
的类。这个线程对象将被用作 JVM 关闭钩子。CustomThread
类实现了 run()
方法。在主类 TestThread
中,我们使用 Runtime.getRuntime().addShutdownHook()
方法添加了一个关闭钩子,通过传递一个线程对象。在输出中你可以验证当程序即将退出时 CustomThread run()
方法被调用。
package com.tutorialspoint;
class CustomThread extends Thread {
public void run() {
System.out.println("JVM is shutting down.");
}
}
public class TestThread {
public static void main(String args[]) throws InterruptedException {
try {
Runtime.getRuntime().addShutdownHook(new CustomThread());
System.out.println("Program is starting...");
System.out.println("Waiting for 3 seconds...");
Thread.sleep(3000);
System.out.println("Program is closing...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
Program is starting...
Waiting for 3 seconds...
Program is closing...
JVM is shutting down.
更多 JVM 关闭钩子示例
示例 1
在这个例子中,我们通过实现 Runnable
接口来创建一个名为 CustomThread
的类。这个线程对象将被用作 JVM 关闭钩子。CustomThread
类实现了 run()
方法。在主类 TestThread
中,我们使用 Runtime.getRuntime().addShutdownHook()
方法添加了一个关闭钩子,通过传递一个线程对象。在输出中你可以验证当程序即将退出时 CustomThread run()
方法被调用。
package com.tutorialspoint;
class CustomThread implements Runnable {
public void run() {
System.out.println("JVM is shutting down.");
}
}
public class TestThread {
public static void main(String args[]) throws InterruptedException {
try {
Runtime.getRuntime().addShutdownHook(new Thread(new CustomThread()));
System.out.println("Program is starting...");
System.out.println("Waiting for 3 seconds...");
Thread.sleep(3000);
System.out.println("Program is closing...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
Program is starting...
Waiting for 3 seconds...
Program is closing...
JVM is shutting down.
示例 2
我们可以使用 removeShutdownHook()
方法来移除关闭钩子。在这个例子中,我们通过实现 Runnable
接口来创建一个名为 CustomThread
的类。这个线程对象将被用作 JVM 关闭钩子。CustomThread
类实现了 run()
方法。在主类 TestThread
中,我们使用 Runtime.getRuntime().addShutdownHook()
方法添加了一个关闭钩子,通过传递一个线程对象。作为最后一步,我们使用 Runtime.getRuntime().removeShutdownHook()
方法移除了钩子。
package com.tutorialspoint;
class CustomThread implements Runnable {
public void run() {
System.out.println("JVM is shutting down.");
}
}
public class TestThread {
public static void main(String args[]) throws InterruptedException {
try {
Thread hook = new Thread(new CustomThread());
Runtime.getRuntime().addShutdownHook(hook);
System.out.println("Program is starting...");
System.out.println("Waiting for 3 seconds...");
Thread.sleep(3000);
System.out.println("Program is closing...");
Runtime.getRuntime().removeShutdownHook(hook);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
Program is starting...
Waiting for 3 seconds...
Program is closing...