netty的线程模型对一个channel来说是单线程的,也就是说这个channel的所有读写事件都是同一个线程执行的,避免了多线程产生的并发问题.而一个eventloop是可以被多个channel绑定的,那么每次服务器连接一个channel之时,netty时如何知道使用哪个线程的呢?
本文描述背景假设对netty的使用比较熟悉,例如 ChannelContext,ChannelPipeline,EventLoopGroup的概念,netty 的网络模型 NIO , netty 的reactor线程模型等.
netty中eventloop线程和客户端管道的绑定是怎么实现的?
netty通过java.nio.channels.SelectableChannel#register(java.nio.channels.Selector, int, java.lang.Object)
方法将自身实现的NioSocketChannel和SelectionKey,原生的socket channel绑定在了一起.
NioSocketChannel(AbstractNioChannel.NioUnsafe负责创建)在初始化过程中(由ServerBootstrapAcceptor
负责添加pipeline等)时会设置eventloop变量的,
这样每次selectionkey事件触发就知道是哪个niosocketchannel,然后就知道了eventloop(执行线程).具体代码实现位置见下文
NioEventLoopGroup初始化时做了什么?
NioEventLoopGroup 是一个多线程池,初始化时根据设置的线程大小依次创建EventLoop对象,EventLoop也是一个线程池抽象,只不过它是单线程的
代码摘要:
NioEventLoopGroup()
MultithreadEventExecutorGroup(...)
for (int i = 0; i < nThreads; i ++) {
EventExecutor[i] = newChild(executor,args)
return (NioEventLoop) NioEventLoopGroup#newChild(...)//注意这里返回的NioEventLoop是整个服务端的boss线程执行入口
}
netty的 ServerChannel 的 register 过程?
通过反射实例化 NioServerSocketChannel , 然后向 nio select 中注册一个 ops=0的selectkey .具体过程见下面代码
代码摘要:
//代码中 this 指的是 NioServerSocketChannel 服务端channel
ServerBootstrap.bind(port)
AbstractBootstrap.doBind(port)
initAndRegister()
//通过反射 NioServerSocketChannel.class生成channel实例
channel