关闭

Netty源码解读之线程

504人阅读 评论(0) 收藏 举报

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)送人管道。




因为ServerBootstrap在初始化NioServerSocketChannel的时候为其pipeline加入了ServerBootstrapAcceptor这个handler。




所以调用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中。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1408372次
    • 积分:21693
    • 等级:
    • 排名:第333名
    • 原创:470篇
    • 转载:1953篇
    • 译文:3篇
    • 评论:69条
    文章分类
    最新评论
    博客推荐
    http://www.vpser.net/