Posted on 2014-11-27 07:36
云自无心水自闲 阅读(9851)
评论(0) 编辑 收藏 所属分类:
Java 、
心得体会
Netty作为一个异步非阻塞式的框架,是不允许在ChannelHandler中长时间处理事务(比如数据库的操作),阻塞I/O的读写处理的。
在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);
我分析原因可能是:在新的连接到来,创建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时候,传入的线程个数参数的大小。