• (二) 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);
    

      

  • 相关阅读:
    DIOCP开源项目详解编码器和解码器和如何在传输中加入压缩和解压功能
    DIOCP开源项目DEMO(怎么样操作远程数据库)
    网站文件更新工具
    使用Javascript正则表达式来格式化XML内容
    加载有命名空间,但没有声名的XML
    使用参数化和块语句来提高批处理SQL语句的执行效率
    让Dotnet识别Java发送来的自定义SoapHeader
    中行的EToken
    异步调用方法时异常的捕获
    使用参数化和块语句来提高批处理SQL语句的执行效率(2)
  • 原文地址:https://www.cnblogs.com/heshana/p/13991685.html
Copyright © 2020-2023  润新知