netty_run_time
2014-10-29 13:29:22 4 举报
登录查看完整内容
netty运行原理分析
作者其他创作
大纲/内容
BossGroup(对象)
if in EventLoop: register0()
SingleThreadEventExecutorexecute(Task)if not inEventLoop: startThread();addTask(task);
AbstractNioMessageChannelNioMessageUnsaferead() { read... pipeline.fireChannelRead();}
NioEventLoopGroup
EventExecutor[] children;Set readonlyChildren;AtomicInteger childIndex;AtomicInteger terminatedChildren;Promise terminationFuture;EventExecutorChooser chooser;
a NioEventLoop object'staskQueue
NioEventLoopviolatile Thread thread;taskQueue;
注意:每个线程只能共享\"创建它\"的NioEventLoop对象所有的一切!!![这也是netty不担心并发的原因]
NioEventLoopvolatile Thread thread;taskQueue;
LoggingHandler.channelRegistered()
注意:这里运行addTask()的NioEventLoop是ChildGroup choose的对象,不一定是当前线程共享的NioEventLoop对象,所以这里可能添加到的是choose的NioEventLoop对象的taskQueue中,跟后续的runAllTask可能没关系!(runAllTasks是运行当前线程所共享的那个NioEventLoop对象的taskQueue)
NioEventLooprun() { // 注意从这里已经脱离了 // 原线程 for(;;) { select(); processSelectedKeys(); runAllTasks(); }}
注意:每个线程只能共享创建它的NioEventLoop对象所有的一切!!![这也是netty不担心并发的原因]
register0()doRegister(); safeSetSuccess(promise);pipeline.fireChannelRegistered();
该函数执行完后,则执行processSelectedKeys()后面的runAllTasks()函数。[如左边线程块所示](注意所run的task都是“创建”该线程的NoiEventLoop对象的task,不会run别的对象的task)
DefaultChannelHandlerInvoker.invokeChannelRegistered()
Abstract-Channel
Channel parent;ChannelId id;volatile boolean registered;volatile SocketAddress localAddress;volatile SocketAddress remoteAddress;Unsafe unsafe;volatile EventLoop eventLoop;DefaultChannelPipeline pipeline;MessageSizeEstimator.Handle estimatorHandle;ChannelFuture succeededFuture;VoidChannelPromise voidPromise;VoidChannelPromise unsafeVoidPromise;CloseFuture closeFuture;
The Thread create by a NioEventLoop(and only share the above NioEventLoop object's value)
childGroupEventExecutor[] children;
init(channel)channel.pipeline.addLast( ServerBootstrapAcceptor { channelRead(); })
OneTimeTaskregister0()
NioEventLoop
EventExecutorGroup parent;Queue taskQueue;Queue delayedTaskQueue;volatile Thread thread;Executor executor;ChannelHandlerInvoker invoker;Selector selector;SelectedSelectionKeySet selectedKeys;SelectorProvider provider;
SingleThreadEventExecutorrunAllTasks() { run all task (运行该NioEventLoop对象中taskQueue存储的所有任务)}
bossGroupEventExecutor[] children;
if not inEventLoop // 注意这里不是立即运行task! eventLoop.execute( new OneTimeTask() { void run() { register0(promise); } } )
ServerBootstrap
startThread()if 该NioEventLoop对象(SingleThreadEventExecutor)没有创建过线程: doStartThread();else: do nothing
Threadfor(;;) { select(); processSelectedKeys(); runAllTasks(); }
ChildGroup(对象)
doBind0()channel.eventLoop().execute( run() { channel.bind() })
// 当select到消息时call backchannelRead()childGroup.register(channel)[从childGroup的children[]中随即选取一个NioEventLoop]
doStartThread()// 这里真正的创建了一个线程!ThreadPerTaskExecutor.execute({ SingleThreadEventExecutor.run();})
[netty采用了类似以前c语言fork线程的生产者消费者模型:生产着消费者都用同一个代码,通过属性进行分辨和控制。而netty这里是通过每个NioEventLoop对象的thread属性来保存它创建的线程值,并通过它识别是否运行在自己创建的线程中(is inEventLoop)。netty采用一个对象(NioEventLoop)创建一个线程的方式来避免同步数据,因为一个线程只能共享创建他的对象的空间,所以3个child(NioEventLoop)对象创建的3个线程,只共享自己对象的空间,不会发生数据竞争等同步问题。]BossGroup对象choose了一个SingleThreadEventExcutor/NioEventLoop对象(只设定了一个)产生了一个线程:NioEventLoop 2-1。该线程进行loop,当select触发了channelRead() childGroup对象choose一个SingleThreadEventExcutor/NioEventLoop对象(测试设定了一个),由于还未创建过线程,所以产生了NioEventLoop 3-1。这两个线程都会同样的运行,只是无论是BossGroup,还是childGroup创建的线程,都完全一样,不会有差别,线程中都会有volatile childGroup对象,而且每当他们拿到select的返回值,都会调用childGroup对象,完全一样。(不会再调用BossGroup)所有的线程都共享多个childGroup创建的SingleThreadEventExcutor/NioEventLoop对象,而每个NioEventLoop对象都有个thread属性,用于记录*他创建*的线程是哪个,当childGroup对象choose了一个NioEventLoop对象时,该对象会用自己属性thread比较current thread,若不是自己创建的线程,则加入到*自己的*taskQueue中,(等待自己的线程被选中。自己被run)???BossGroup的作用仅仅是发起一个线程,好触发childGroup。所以BossGroup设置为1,设置多个没有用,因为运行一个线程后,就会只调用childGroup对象了。不会再调用BossGroup对象了。
initAndRegister()channelFactory().newChannel()init(channel)group.register(newChannel)
DefaultChannelPipeline.HeadContext.fireChannelRegistered()
ChannelHandlerInvokerUtil.invokeChannelRegisteredNow()
DefaultChannelHandlerContext.fireChannelRegistered()
AbstractChannelregister(eventLoop)
注意:由BossGroup创建的NioEventLoop对象,由于每次触发read时是触发childGroup创建/choose的NioEventLoop对象,所以对于childGroup创建的NioEventLoop对象来说,in EventLoop始终为false。(因为childGroup创建的NioEventLoop对象不会对应BossGroup创建的NioEventLoop对象创建的线程...),所以每次BossGroup创建的NioEventLoop对象创建的线程只是将task保存到choose到的NioEventLoop对象的task中,不会自己处理。【参看上面截取的运行片段】
收藏
收藏
0 条评论
回复 删除
下一页