Netty作為一個異步非阻塞式的框架,是不允許在ChannelHandler中長時間處理事務(比如數據庫的操作),阻塞I/O的讀寫處理的。
在Netty in Action中是這樣描述的:
在Netty in Action中是這樣描述的:
While the I/O thread must not be blocked at all, thus prohibiting any direct blocking operations within your ChannelHandler, there is a way to implement this requirement.
You can specify an EventExecutorGroup when adding ChannelHandlers to the ChannelPipeline.
This EventExecutorGroup will then be used to obtain an EventExecutor, which will execute all the methods of the ChannelHandler.
This EventExecutor will use a different thread from the I/O thread, thus freeing up the EventLoop.
I/O線程是不允許被阻塞的,也就是不能在ChannelHandler中進行任何阻塞式的處理,但是對此我們也有相應的解決方法.
就是在把ChannelHanders添加到ChannelPipeline的時候,指定一個EventExecutorGroup,ChannelHandler中所有的方法都將會在這個指定的EventExecutorGroup中運行。
而這個EVentExecutorGroup運行的線程與I/O線程不同,達到不阻塞I/O的目的。
程序示例如下:
Channel ch = ...;
ChannelPipeline p = ch.pipeline();
EventExecutor e1 = new DefaultEventExecutorGroup(16);
EventExecutor e2 = new DefaultEventExecutorGroup(8);
p.addLast(new MyProtocolCodec());
p.addLast(e1, new MyDatabaseAccessingHandler());
p.addLast(e2, new MyHardDiskAccessingHandler());
需要補充說明一下,上面的示例程序似乎有點問題。使用上述方法添加ChannelHandler到pipeline中以后,channelHandler的所有方法確實什么在一個單獨的線程中被處理。
但是,每次DefaultEventExcutorGroup線程池中的線程不能被重用,每次都會生成一個新的線程,然后在新的線程中調用ChannelHandler, 在visualvm可以看到線程數量直線增長。
解決的方法是:不能使用局部變量形式的DefaultEventExecutorGroup。而使用類靜態成員變量:
static final EventExecutor e1 = new DefaultEventExecutorGroup(16);
需要補充說明一下,上面的示例程序似乎有點問題。使用上述方法添加ChannelHandler到pipeline中以后,channelHandler的所有方法確實什么在一個單獨的線程中被處理。
但是,每次DefaultEventExcutorGroup線程池中的線程不能被重用,每次都會生成一個新的線程,然后在新的線程中調用ChannelHandler, 在visualvm可以看到線程數量直線增長。
解決的方法是:不能使用局部變量形式的DefaultEventExecutorGroup。而使用類靜態成員變量:
static final EventExecutor e1 = new DefaultEventExecutorGroup(16);
我分析原因可能是:在新的連接到來,創建ChannelPipeline給新Channel的時候,如果不使用靜態的共享變量,而使用局部變量的話,就造成DefaultEventExecutorGroup被多次重復創建。因此,雖然一個DefaultEventExecutorGroup中的Thread數量是固定的,但是卻產生了多余的DefaultEventExecutorGroup。從VisualVM中也可以看到,DefaultEventExecutorGroup線程的名字會是:
xxx-2-1
xxx-3-1
xxx-4-1
xxx-n-1
說明是Group的數量(第一個數字)在增多,而不是Group中的線程數量(第二個數字)在增多
改成靜態變量后,線程名會是:
xxx-2-1
xxx-2-2
xxx-2-3
xxx-2-n
最后一個n就是在創建DefaultEventExecutorGroup時候,傳入的線程個數參數的大小。