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