Java程序的安全退出
一、原理
Signal实例表示一个信号量实例
将Signal实例注册到SignalHandler中实现对该信号量的监听
当监听到信号量,就会回调handle方法
特别注意:安全退出是通过监听信号量回调方法运行,并不是让程序退出。而其他方法是程序主动关闭,会停止其他线程运行shudownhook线程进行扫尾关闭
二、它和关闭钩子的区别
1、关闭钩子:会终止main线程让整个程序停下来后执行shutdownHook线程进行扫尾工作、
2、监听信号量:系统发送信号量以后,会先被Java程序中的监听程序线程捕获信号量,不影响main线程的继续运行,可以在其中调用System.exit(0)来关闭程序,这个时候就会正常关闭程序,运行shutdownhook线程
三、例子
public class ShutdownTest {
public static void main(String[] args) {
System.out.println("Shutdown Test");
Signal sg = new Signal("TERM"); // kill -15 pid
// 监听信号量
//将sg这个信号量实例注册到一个SignalHandler实例中
Signal.handle(sg, new SignalHandler() {
//收到指定信号量就回调handle()方法
@Override
public void handle(Signal signal) {
System.out.println("signal handle: " + signal.getName());
System.exit(0);
}
});
// 注册关闭钩子
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
// 在关闭钩子中执行收尾工作
// 注意事项:
// 1.在这里执行的动作不能耗时太久
// 2.不能在这里再执行注册,移除关闭钩子的操作
// 3 不能在这里调用System.exit()
System.out.println("do shutdown hook");
}
});
mockWork();
System.out.println("Done.");
System.exit(0);
}
// 模拟进程正在运行
private static void mockWork() {
//mockRuntimeException();
//mockOOM();
try {
Thread.sleep(120 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 模拟在应用中抛出RuntimeException时会调用注册钩子
private static void mockRuntimeException() {
throw new RuntimeException("This is a mock runtime ex");
}
// 模拟应用运行出现OOM时会调用注册钩子
// -xms10m -xmx10m
private static void mockOOM() {
List list = new ArrayList();
for(int i = 0; i < 1000000; i++) {
list.add(new Object());
}
}
}