EventLoopGroup和EventLoop的创建
EventLoopGroup构造方法参数有两个一个是线程数一个是executor
- 如果不给线程数默认先读取系统变量io.netty.eventLoopThreads对应的值,如果没有则取cpu核数*2个
- 如果executor不给定则默认使用ForkJoinPool作为executor,并行数为上述值
先看一张NioEventLoopGroup继承图
###构造方法路径
NioEventLoopGroup->MultithreadEventLoopGroup->MultithreadEventExecutorGroup
最终使用下面的代码,非关键代码不一一列举
private MultithreadEventExecutorGroup(int nEventExecutors,
Executor executor,
boolean shutdownExecutor,
Object... args) {
//1参数校验
//2如果executor为空创建默认的ForkJoinPool
//创建EventLoop
children = new EventExecutor[nEventExecutors];
for (int i = 0; i < nEventExecutors; i ++) {
boolean success = false;
try {
//newChild方法在NioEventLoopGroup中实现,args是SelectorProvider
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
} finally {
//3如果不成功关闭所有的
}
}
//4给EventLoop的终止增加回调函数
//5把children变成只读
}
NioEventLoopGroup中实现newChild方法
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0]);
}
EventLoop继承关系图
NioEventLoop.java
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider) {
super(parent, executor, false);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
}
provider = selectorProvider;
selector = openSelector();
}
super中的第三个参数在SingleThreadEventExecutor构造函数中体现,当该值为true
时,当且仅当调用addTask(Runnable)
方法才会唤醒executor的线程,同时在SingleThreadEventExecutor构造方法中也创建了一个无界队列LinkedBlockingQueue<Runnable>()
回到NioEventLoop构造方法发现每创建一个EventLoop都会打开一个Selector。
总结
- EventLoopGroup从名字可以看出是用来创建和管理EventLoop。
- EventLoopGroup有很多种,通用的是NioEventLoopGroup,还有依赖操作系统支持的EpollEventLoopGroup,在linux系统下推荐使用EpollEventLoopGroup 回答的是netty in action的作者
- new一个EventLoopGroup的过程实际上就是一个创建多个EventLoop的过程
- 每创建一个EventLoop都要打开一个Selector,所以new的时候不要用过大的nThreads参数,EventLoop只负责读写数据,耗时的IO操作应该交给另一个线程池来处理。