上一篇介绍了Netty的Reactor模型,这一篇,聊一聊Netty中的线程池模型——NioEventLoopGroup。
先上NioEventLoopGroup的类图:
可以说NioEventLoopGroup类的继承体系还是很复杂的,我们需要搞清楚的事情是,NioEventLoopGroup是MultithreadEventLoopGroup的子类,而MultithreadEventLoopGroup的父类是MultithreadEventExecutorGroup,再往上看它的父类是ExecutorService,ExecutorService是一个线程池啊。
在上一篇中,启动一个NettyServer,我们首先创建了两个NioEventLoopGroup,那就先看一下NioEventLoopGroup的初始化过程都做哪些工作。
在NioEventLoopGroup的构造器中,通过调用父类构造器,最终在MultithreadEventExecutorGroup中,创建了Executor以及一个名为children的EventExecutor数组,数组大小为nThreads。
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
//创建执行器,eventLoopGroup中的executor,这个executor会为每一个channel创建一个线程执行对应的任务,后面还会看到,eventLoopGroup中的每个eventLoop,也包含一个executor
if (executor == null) {//NioEventLoopGroup构造器中如果定义类ThreadFactory,则这里就不会再执行了,会在子类直接创建executor,当前区别是定义了线程名字
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//eventLoopGroup中包含一个eventExecutor的数组,数组里面是NioEventLoop的实例,每个NioEventLoop中包含一个executor,一个selector
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args); //创建NioEventLoop
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
NioEventLoopGroup的构造器,可以指定线程数,还可以指定线程工厂,为线程池起个名字,上一篇中,我们就是通过指定的线程工厂为bossGroup和workerGroup指定了线程池名称,这样也方便我们通过jvisualvm来查看不同线程池的线程数。
如果不指定线程数量,Netty会使用服务器逻辑内核数的两倍作为默认线程数.
通过NioEventLoopGroup#newChild()方法,创建NioEventLoop的数组,这里我们发现一个很有意思的情况,NioEventLoopGroup是executor,NioEventLoop也是executor,你心里是否有一堆问号?看一下NioEventLoop的类图:
看一下NioEventLoop的构造器:
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
EventLoopTaskQueueFactory queueFactory) {
super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory),
rejectedExecutionHandler);
this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");
this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");
final SelectorTuple selectorTuple = openSelector();
this.selector = selectorTuple.selector;
this.unwrappedSelector = selectorTuple.unwrappedSelector;
}
一个NioEventLoopGroup中包含一个executor,一个NioEventLoop的数组;一个NioEventLoop中包含一个selector,一个provider,这两个都是JDK的NIO中提供的,还有一个taskQueue;NioEventLoopGroup和NioEventLoop本身也都是executor。OMG!!!
SingleThreadEventExecutor内部有一个thread,这其实是Netty对本地线程的一种封装,我们可以认为,一个NioEventLoop与一个线程绑定,并且在NioEventLoop的生命周期内,绑定的thread都不会改变。
这一篇就先简单的介绍到这里,下一篇我们具体看看NioEventLoopGroup线程池,如何处理客户端请求。