在Linux上一般会经过kill -9 pid的方式强制将某个进程杀掉,这种方式简单高效,所以不少程序的中止脚本常常会选择使用kill -9 pid的方式。数据库
不管是Linux的Kill -9 pid仍是windows的taskkill /f /pid强制进程退出,都会带来一些反作用:对应用软件而言其效果等同于忽然掉电,可能会致使以下一些问题:windows
Java的优雅停机一般经过注册JDK的ShutdownHook来实现,当系统接收到退出指令后,首先标记系统处于退出状态,再也不接收新的消息,而后将积压的消息处理完,最后调用资源回收接口将资源销毁,最后各线程退出执行。缓存
一般优雅退出须要有超时控制机制,例如30S,若是到达超时时间仍然没有完成退出前的资源回收等操做,则由停机脚本直接调用kill -9 pid,强制退出。异步
要实现Netty的优雅退出,首先须要了解通用Java进程的优雅退出如何实现。下面咱们先讲解下优雅退出的实现原理,并结合实际代码进行讲解。最后看下如何实现Netty的优雅退出。ide
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求能够说是同样的,它oop
是进程间一种异步通讯的机制。以Linux的kill命令为例,kill -s SIGKILL pid (即kill -9 pid) 当即杀死指定pid的进程,SIGKILL就是发送给pid进程的信号。测试
信号具备平台相关性,Linux平台支持的一些终止进程信号以下所示:操作系统
Windows平台存在一些差别,它的一些信号举例以下:SIGINT(Ctrl+C中断)、SIGILL、SIGTERM (kill发出的软件终止)、SIGBREAK (Ctrl+Break中断)。线程
信号选择:为了避免干扰正常信号的运做,又能模拟Java异步通知,在Linux上咱们须要先选定一种特殊的信号。经过查看信号列表上的描述,发现 SIGUSR1 和 SIGUSR2 是容许用户自定义的信号,咱们能够选择SIGUSR2,为了测试方便,在Windows上咱们能够选择SIGINT。code
首先看下通用的Java进程优雅退出的流程图:
Signal sig = new Signal(getOSSignalType());
private String getOSSignalType() { return System.getProperties().getProperty("os.name"). toLowerCase().startsWith("win") ? "INT" : "USR2"; }
判断是不是windows操做系统,若是是则选择SIGINT,接收Ctrl+C中断的指令;不然选择USR2信号,接收SIGUSR2(等价于kill -12 pid)指令。
Signal.handle(sig, shutdownHandler);
其中shutdownHandler实现了SignalHandler接口的handle(Signal sgin)方法,代码示例以下:
private void invokeShutdownHook() { Thread t = new Thread(new ShutdownHook(), "ShutdownHook-Thread"); Runtime.getRuntime().addShutdownHook(t); }
Runtime.getRuntime().exit(0);
虚拟机退出时,底层会自动检测用户是否注册了ShutdownHook任务,若是有,则会自动将ShutdownHook线程拉起,执行它的Run方法,用户只须要在ShutdownHook中执行资源释放操做便可,示例代码以下:
class ShutdownHook implements Runnable { @Override public void run() { System.out.println("ShutdownHook execute start..."); System.out.print("Netty NioEventLoopGroup shutdownGracefully..."); try { TimeUnit.SECONDS.sleep(10);//模拟应用进程退出前的处理操做 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ShutdownHook execute end..."); System.out.println("Sytem shutdown over, the cost time is 10000MS"); } }
下面咱们在Windows环境中对通用的Java优雅退出程序进行测试,打开CMD控制台,拉起待测试程序,以下所示:
启动进程:
查看线程信息,发现注册的ShutdownHook线程没有启动,符合预期: