标签:netty nio 线程
Netty源码解读之线程
本文主要测试代码如下:
先关注下NioEventLoopGroup和NioEventLoop类关系:
在创建NioEventLoopGroup对象之前先执行NioEventLoopGroup父类静态模块,计算出默认的线程个数,电脑配置为四线程,所以默认为8个线程。
进入NioEventLoopGroup构造,并且传递java.nio.channels.spi.SelectorProvider到构造中。
最后调用父类MultithreadEventLoopGroup构造
将默认的线程数传入父类MultithreadEventExecutorGroup构造中
terminationFuture最终实现的是java.util.concurrent.RunnableFuture<V>接口,负责最后释放资源。
回到MultithreadEventExecutorGroup的构造
Executor 是线程执行的核心。若为空则需要创建ThreadPerTaskExecutor替代。
ThreadPerTaskExecutor实现了java.util.concurrent.Executor接口
ThreadPerTaskExecutor中的ThreadFactory成员变量由DefaultThreadFactory生成,DefaultThreadFactory实现了java.util.concurrent.ThreadFactory接口
最后所有的EventLoop都由NioEventLoopGroup里的newChild方法实现:
children[i] =newChild(executor, args);并且给EventLoop传入executor和SelectorProvider。
executor最终传到NioEventLoop的父类SingleThreadEventExecutor里。
现在EventLoopGroup和EventLoop创建完成,EventLoop仍未执行,ServerBootstrap完成NioServerSocketChannel的初始化后会时候会异步注册NioServerSocketChannel到Reactor线程的多路复用器上,用来监听ACCEPT。
execute执行方法,若EventLoop未启动,调用启动函数startThread。
在延时任务队列中加入清理任务,调用启动函数doStartThread。
doStartThread方法中executor调用execute方法,实际上调用的是ThreadPerTaskExecutor中的execute方法,start一个实际的线程。
在线程中实际运行的run方法SingleThreadEventExecutor.this.run();存在于子类NioEventLoop中,如下图:
这样NioEventLoopGroup(boss)中的NioServerSocketChannel(ACCEPT)线程就运行起来了,实际上bind一个端口就只会启动一个boss线程。NioEventLoopGroup(woker)的工作方式和boss完全一样,启动方式略有不同,要说明白先要梳理下nio socket的创建流程。
先关注下NioChannel的类图:
上面线程中的run方法,真正调用的方法是:processSelectedKeysOptimized(selectedKeys.flip());
依据channel关心的操作执行unsafe操作,ACCEPT和READ都执行unsafe.read();
以NioServerSocketChannel为例,关心ACCEPT操作,同样执行unsafe.read(),如下:
NioServerSocketChannel中的doReadMessages操作如下:
childEventLoopGroup().next()是为了保证所有的连接(NioSocketChannel)会均匀的绑定到8个线程上。
回到NioServerSocketChannel的unsafe.read()
接下来NioServerSocketChannel的pipeline把读到的内容(ClientChannel)送人管道。
由于NioServerSocketChannel在bind的时候初始化的ChannelInitializer中给pipeline加入的handler为ServerBootstrapAcceptor。
所以调用pipeline的channelRead方法是执行clientChannel(NioSocketChannel)的注册过程。
先将clientChannel的pipeline加入ChannelInitializer(childHandler),然后执行clientChannel的注册过程
最后NioSocketChannel会调用AbstractNioChannel的doRegister方法,
将clientChannel(NioSocketChannel)注册到eventloop的selector上
同样clientChannel的register采用自身的eventLoop.execute()的异步执行,所以clientChannel所绑定的线程也要开始运行了,数据来到的时候,线程执行unsafe.read(注意:NioSocketChannel的unsafe.read和NioServerSocketChannel的不同)会将数据放入管道pipeline中。
标签:netty nio 线程
原文地址:http://blog.csdn.net/handsome_926/article/details/38896011