最近看《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);