netty源码之NioEventLoop
Posted better_hui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了netty源码之NioEventLoop相关的知识,希望对你有一定的参考价值。
目录
1、NioEventLoopGroup最终都是调用父类MultithreadEventLoopGroup的构造器
3、newChild()方法实例化的是NioEventLoop类型的EventLoop对象
1、客户端在通过bootstrap启动时会创建一个Channel实例并进行初始化,在初始化过程中会绑定一个NioEventLoop
2、NioEventLoopGroup调用父类的register()方法将获取一个EventLoop与通道绑定
4、调用AbstractChannel的register0()方法最终完成通道的注册
一、初始化
ServerBootstrap b = new ServerBootstrap();
EventLoopGroup bossGroup = new NioEventLoopGroup(); //创建多线程线程池
EventLoopGroup workGroup = new NioEventLoopGroup(); //创建多线程线程池
b.group(bossGroup,workGroup);
服务端的acceptor ,处理IO事件分两种:监听请求建立连接 和 处理连接 。
在reactor多线程模型下 , 两种事件都是有同一个线程处理。
在reactor主从线程模型下 , bossGroup负责处理监听连接事件 , workerGroup负责处理连接
1、NioEventLoopGroup最终都是调用父类MultithreadEventLoopGroup的构造器
protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args)
super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
2、通过父类MultiThreadEventExecutorGroup构造器创建NioEventLoopGroup实例,内部维护了一个SingleThreadEventExecutor类型的数组,通过newChild()方法进行实例化
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args)
// 创建一个线程池
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
// 创建一个NioEventLoop数组
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++)
children[i] = newChild(executor, args);
// 生成一个线程选择器
chooser = chooserFactory.newChooser(children);
3、newChild()方法实例化的是NioEventLoop类型的EventLoop对象
NioEventLoop类继承了SingleThreadEventExecutor类 , 该类种有一个thread属性 ,用以绑定本地线程
protected EventLoop newChild(Executor executor, Object... args) throws Exception
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
4、NioEventLoop 打开一个selector
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler)
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
if (selectorProvider == null)
throw new NullPointerException("selectorProvider");
if (strategy == null)
throw new NullPointerException("selectStrategy");
provider = selectorProvider;
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
二、EventLoop 与 Channel的关系
1、客户端在通过bootstrap启动时会创建一个Channel实例并进行初始化,在初始化过程中会绑定一个NioEventLoop
-> AbstractBootstrap.initAndRegister()
-> channelFactory.newChannel()
-> group().register(channel)
-> MultiThreadEventLoopGroup.regiser()
2、NioEventLoopGroup调用父类的register()方法将获取一个EventLoop与通道绑定
public ChannelFuture register(Channel channel)
return this.next().register(channel);
3、最终调用了 AbstractChannel#AbstractUnsafe.register 后完成了 Channel 和 EventLoop 的关联,将获取的EventLoop值赋值给AbstractChannel内的一个eventLoop属性
public final void register(EventLoop eventLoop, final ChannelPromise promise)
// 删除条件检查.
...
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop())
register0(promise);
else
try
eventLoop.execute(new OneTimeTask()
@Override
public void run()
register0(promise);
);
catch (Throwable t)
...
4、调用AbstractChannel的register0()方法最终完成通道的注册
private void register0(ChannelPromise promise)
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
if (firstRegistration && isActive())
pipeline.fireChannelActive();
protected void doRegister() throws Exception
// 省略错误处理
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
以上是关于netty源码之NioEventLoop的主要内容,如果未能解决你的问题,请参考以下文章
死磕Netty源码之Reactor线程模型详解NioEventLoop的执行