(二) netty服务端意外退出 之 优雅退出

最近看《netty进阶之路》这本书,记一下笔记心得,以后逐步完善…………

服务端代码

final Handler serverHandler = new Handler();
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();

try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(serverHandler);
}
});
ChannelFuture future = b.bind(18080).sync();

} finally {
System.out.println("final");
bossGroup.shutdownGracefully().sync();
workGroup.shutdownGracefully().sync();
}

  运行结果套接字关闭、进程退出。具体原因进行分析.

 netty 启动原理:

先反复验证 :

屏蔽finally 中的关闭代码 ,如上图(才发现idea 这个小功能,可以看dump,这几个小按钮也是功能强大) ,打开后可以发现有5个线程, 其中有3个daemon(守护线程) ,守护线程决定不了程序的结束,先不管。还有NioEventLoopGroup 和DestroyJavaVM , 这个DestroyJavaVm 好像是程序结束时销毁虚拟机用的,现在只有NioEventLoopGroup阻塞了进程, 上述finally 中刚好有2个关闭Group的操作,所以这时候程序退出。

  以上是结果 , 说明在bind操作,会进行端口绑定,同时有同步阻塞。 在finally执行group.shutdownGracefully(),会关闭tcp接入线程池(bossGroup)和处理io工作线程池(workGroup)。

  如何防止netty服务断意外退出:

  不优雅关闭group肯定是不行的,那程序只能暴力kill,会导致消息处理异常。具体操作方法如下

    程序监听NioServerSocketChannel的关闭事件,同时阻塞mian函数:

    

 ChannelFuture future = b.bind(18080).sync();
            future.channel().closeFuture().sync();

  main函数一直阻塞,后续finally不被执行,程序不会退出。

  这样貌似解决了问题,但是最近发现在业务系统中激活此服务后,主调用线程被阻塞了,也就是业务系统被卡住了…… 

  将代码进行如下修改,服务端启动后注册监听关闭事件,待服务关闭异步调用shutdownGracefull释放资源,这样调用方线程可以快速返回。

            ChannelFuture future = b.bind(18080).sync();
            future.channel().closeFuture(). addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    bossGroup.shutdownGracefully().sync();
                    workGroup.shutdownGracefully().sync();
                }
            });
        } finally {
            System.out.println("final");
//            bossGroup.shutdownGracefully().sync();
//            workGroup.shutdownGracefully().sync();
        }

  方法二:jvm的shutDownHook

    Runtime.getRuntime().addShutdownHook(new Thread(
                    ()->{
                        System.out.println("shut down Hook execute start ^");
                        try{
                            TimeUnit.SECONDS.sleep(3);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                        System.out.println("shut down Hook execute end ^");
                    },""
            ));
            TimeUnit.SECONDS.sleep(7);
            System.out.println("System.exit ^");
            System.exit(0);

  

原文地址:https://www.cnblogs.com/heshana/p/13991685.html