在开发中,遇到一个问题。我们每次重启一个应用的时候,总会导致一些正在执行的任务因为机器突然死掉,如果不对这种正在执行的任务记录,处理的话,这些任务就消失了。在重启那个时刻jvm里所发生的所有事情我们都已无所知。这会导致什么样的后果,很难知道。发生的后果也难以管理。所以必须对这种情况进行监控,处理。
后来知道了java的addShutdownHook钩子函数,试了试,很管用。下面是这个函数的官方中文API:
Java 虚拟机会为了响应以下两类事件而关闭
:
-
程序正常退出
,这发生在最后的非守护线程退出时,或者在调用
exit
(等同于 System.exit
)方法时。或者,
-
为响应用户中断而终止
虚拟机,如键入 ^C
;或发生系统事件,比如用户注销或系统关闭。
关闭钩子
只是一个已初始化但尚未启动的线程。虚拟机开始启用其关闭序列时,它会以某种未指定的顺序启动所有已注册的关闭钩子,并让它们同时运行。运行完所有的钩子
后,如果已启用退出终结,那么虚拟机接着会运行所有未调用的终结方法。最后,虚拟机会暂停。注意,关闭序列期间会继续运行守护线程,如果通过调用 exit
方法来发起关闭序列,那么也会继续运行非守护线程。
一旦开始了关闭序列,则只能通过调用 halt
方法来停止这个序列,此方法可强行终止虚拟机。
一旦开始了关闭序列,则不可能注册新的关闭钩子或取消注册先前已注册的钩子。尝试执行这些操作会导致抛出 IllegalStateException
。
关闭钩子可在虚拟机生命周期中的特定时间运行,因此应保护性地对其进行编码。特别是应将关闭钩子编写为线程安全的,并尽可能地避免死锁。关闭钩子还应该不
盲目地依靠某些服务,这些服务可能已注册了自己的关闭钩子,所以其本身可能正处于关闭进程中。例如,试图使用其他基于线程的服务(如 AWT
事件指派线程)可能导致死锁。
关闭钩子应该快速地完成其工作。当程序调用 exit
时,虚拟机应该迅速地关闭并退出。由于用户注销或系统关闭而终止虚拟机时,底层的操作系统可能只允许在固定的时间内关闭并退出。因此在关闭钩子中尝试进行任何用户交互或执行长时间的计算都是不明智的。
与其他所有线程一样,通过调用线程 ThreadGroup
对象的 uncaughtException
方法,可在关闭钩子中处理未捕获的异常。此方法的默认实现是将该异常的堆栈跟踪打印至 System#err
并终止线程;它不会导致虚拟机退出或暂停。
仅在很少的情况下,虚拟机可能会中止
,也就是没有完全关闭就停止运行。虚拟机被外部终止时会出现这种现象,比如在 Unix 上使用 SIGKILL
信号或者在 Microsoft Windows 上调用 TerminateProcess
。如果由于内部数据结构损坏或试图访问不存在的内存而导致本机方法执行错误,那么可能也会中止虚拟机。如果虚拟机中止,则无法保证是否将运行关闭钩子。
自己写了个测试的东西,大概讲了怎么使用:
主类:
public class TestHook {
public static void main(String[] args) {
TestDO td = new TestDO();
TestHook th = new TestHook();
th.doSomething();
System.exit(0);
}
public void doSomething() {
System.out.println("doSomething");
}
}
注册钩子的类:
public class TestDO {
TestDO() {
System.out.println("registe");
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("log");
}
});
}
}
很显然,结果是:
registe
doSomething
log
这只是一个很简单的例子,在实际开发中,我是直接写了一个注册类,构造函数为执行addShutdownHook(),把它配置为一个spring的bean。直接交由Spring去管理。值得注意的是,对某些突然直接杀死jvm进程的操作,钩子函数也是不靠谱的,比如Linux命令: kill -9
使用钩子函数有个千万要注意
的地方,如果你在钩子内写了死循环,会发生永远不会执行结束的情况,那系统会永远无法按照正常情况关闭。只能杀java进程了!如:
public class Test {
public Test() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("log");
while (true) {
System.out.println("杯具大了");
}
}
});
}
public static void main(String[] args) {
Test t = new Test();
System.exit(0);
}
}
分享到:
相关推荐
例如,`java.lang.Runtime.addShutdownHook()` 方法可以注册一个线程作为JVM关闭的钩子,当JVM正常退出时,这些钩子线程会被执行,可以用来进行资源清理等操作。 “反射”是Java的一项强大功能,它允许程序在运行时...
JDK在1.3之后提供了Java Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在以下几种场景被调用: 1)程序正常退出 2)使用System.exit() 3)终端使用Ctrl+C触发的...
添加和移除钩子是通过`Runtime`类的`addShutdownHook`和`removeShutdownHook`方法完成的。这两个方法首先会检查当前安全管理者是否允许操作关闭钩子,然后使用`ApplicationShutdownHooks`类来管理这些钩子。 `...
- 在Java中,`Runtime.addShutdownHook()`方法用于注册一个线程作为关闭钩子。当JVM接收到退出信号时,这些钩子会被执行。 - 关闭钩子的执行顺序是不确定的,因此不应依赖它们之间的相对执行时间。 2. **Tomcat中...
这个Java类可能包含了一个钩子函数,当接收到`SIGHUP`时,能够安全地执行必要的更新,如重新初始化配置,但保持已打开的连接和服务状态不变。 【标签】"开源项目" 指的是这两个压缩包都属于开放源代码的项目。这...
15. **关闭钩子(Shutdown Hook)**:通过`Runtime.getRuntime().addShutdownHook(Thread hook)`注册自定义的关闭钩子,这些钩子在JVM关闭时执行,用于清理资源。 16. **精灵线程(Daemon Thread)**:精灵线程是不...
ShutdownHook 是 Java 语言提供的一种钩子机制,当 JVM 接受到系统的关闭通知之后,调用 ShutdownHook 内的方法,用以完成清理操作,从而平滑的退出应用。这种有计划平滑的关闭应用相对直接停止应用,就显得非常...
可以使用`Runtime.getRuntime().addShutdownHook(Thread hook)`来添加一个钩子。 5. **Spring Boot应用关闭**: - 如果"shutdown-app"是在Spring Boot环境下,那么可能涉及到`@PreDestroy`注解,它标记在方法上,...
例如,在上面的代码中,当使用`Runtime.getRuntime().addShutdownHook()`方法注册了一个新的线程,当接收到系统关闭信号时,这个钩子函数会被调用,从而允许执行一些清理工作,如关闭数据库连接、资源释放等。...
Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { server.stop(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); } Or ...
- `getRuntime().addShutdownHook(Thread hook)`: 注册一个关闭钩子,当JVM准备终止时,会调用该线程。 - `destroyForcibly()`: 强制停止由`exec`方法启动的进程。 5. **垃圾收集**: - `gc()`: 请求垃圾收集器...
- 注册 shutdown 守护进程:`Runtime.getRuntime().addShutdownHook(shutdownHook);`。 - 调用 `await()` 方法监听指定端口(默认为 8080),等待 shutdown 命令的到来以关闭 Tomcat。 #### Catalina 类详解 `...
使用addShutDownHook()附加到客户端进程的线程处理用户中止。 这个线程在Client.java被定义为一个内部类。 处理用户离开/加入服务器或 MUD,使用MUDServerMainline的shutdownhook MUDServerMainline和服务器端方法...
SpringBoot Rest与以下库中的JVM Futures结合 ... Runtime.getRuntime().addShutdownHook(new Thread(SpringBootFuturesSimulation::shutdown)); new SpringApplicationBuilder(SpringWebFuturesAppl
1 增加线程池consumer优雅退出机制Runtime.getRuntime().addShutdownHook 2 修改部分log输出方式,将原来的 log.info("exceptin:" + e) 修复为 log.info("exception: ", e) 20161227 更新 1 bug fix: 将...
通常,这些钩子用于进行必要的资源清理,例如关闭文件流、数据库连接等。通过调用`Runtime.getRuntime().addShutdownHook(Thread t)`方法,可以将一个已经初始化但尚未开始执行的线程作为`shutdown hook`注册到JVM中...
你可以通过`Runtime.getRuntime().addShutdownHook(Thread hook)`注册自定义的`Thread`,在程序退出前进行必要的清理工作,如关闭文件流、释放网络连接等。 此外,Java还提供了`Thread.stop()`和`Thread.interrupt...
- `addShutdownHook(Thread hook)`: 注册一个程序关闭钩子,当JVM准备退出时,这些钩子会被调用。 总的来说,Java的Runtime类是Java程序与运行环境交互的重要工具,它提供了一系列方法,使得开发者能够更好地管理...
1. addShutdownHook(Thread hook):注册新的虚拟机来关闭挂钩。 2. availableProcessors():向 Java 虚拟机返回可用处理器的数目。 3. exec(String command):在单独的进程中执行指定的字符串命令。 4. exec(String...
在`DaemonRunner`示例中,我们添加了一个关闭钩子,当主线程结束时,会输出“JVM退出”并稍作延迟,确保相关资源得以释放。 总之,Java中的后台线程是程序中提供服务但不影响程序生命周期的线程。正确理解和使用...