Daemon线程
// 若应用的所有非守护线程都结束则程序退出,守护线程会随之自动退出
Thread t = new Thread();
t.setDaemon(false); // 设为非守护线程,默认为false
t.setDaemon(true); // 设为守护线程
Java优雅退出机制
1.通过注册JDK的ShutdownHook实现
public static void main(String [] args) throws Exception
{
Runtime.getRuntime().addShutdownHook(new Thread(()->
{
System.out.println("ShutdownHook execute start...");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ShutdownHook execute end...");
},""));
TimeUnit.SECONDS.sleep(7);
System.exit(0);
}
2.通过注册信号量实现
// 判断操作系统,确定信号量赋值
String sigStr = System.getProperties().getProperty("os.name").toLowerCase().startsWith("win") ? "INT":"TERM";
Signal sig = new Signal(sigStr);
// 注册到JDK的Signal,一旦java接收到kill pid或Ctrl+C,会回调handler接口
Signal.handle(sig, (s)->{
System.out.println("Signal handle start...");
try {
// 这里是为了模拟错误情况,这样写会阻塞住进程退出,模拟时请去掉
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Runtime.getRuntime().addShutdownHook(new Thread(()->
{
System.out.println("ShutdownHook execute start...");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ShutdownHook execute end...");
},""));
// 开启一个线程防止程序退出
new Thread(new Runnable() {
public void run() {
try {
TimeUnit.DAYS.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();}}
}, "Daemon-T").start();
优雅退出注意点:
- shutdownHook在JVM崩溃、无法接收信号量和kill -9 pid时候不会被回调
- 多个shutdownHook时,JVM无法保证执行顺序
- 在JVM关闭期间,不能添加或删除shutdownHook
- 不能在shutdownHook中调用System.exit(),否则会阻塞shutdownHook
Netty优雅退出
为什么要优雅退出
- 尽快释放NIO线程和句柄等资源
- 如果使用flush做批量纤细发送,需要将积压在发送队列中的待发送消息发送完成
- 正在写或者读的消息需要继续处理
- 设置在NioEventLoop线程调度器中的定时任务需要执行或者清理
如果进行优雅退出
-
把NIO线程的状态位设置成ST_SHUTTING_DOWN,不再处理新的消息,也不允许再对外发送消息
-
推出前的预处理操作:把发送队列中尚未发送或者正在发送的消息发送完(但不保证成功),把已经到期或者在退出之前到期的定时任务执行完成,把用户注册到NIO线程的退出Hook任务执行完成
-
资源释放操作:所有Channel的释放,多路复用器的去注册和关闭,所有队列和定时任务的清空取消,最后是EventLoop线程的退出

493

被折叠的 条评论
为什么被折叠?



